Merge "Adding calling package name options fields"
diff --git a/.idea/.name b/.idea/.name
deleted file mode 100644
index ca48adf..0000000
--- a/.idea/.name
+++ /dev/null
@@ -1 +0,0 @@
-support (master)
\ No newline at end of file
diff --git a/app-toolkit/.idea/.name b/app-toolkit/.idea/.name
deleted file mode 100644
index 3a1feaa..0000000
--- a/app-toolkit/.idea/.name
+++ /dev/null
@@ -1 +0,0 @@
-app-toolkit (master)
\ No newline at end of file
diff --git a/app-toolkit/init.gradle b/app-toolkit/init.gradle
index 654f65c..d3d7754 100644
--- a/app-toolkit/init.gradle
+++ b/app-toolkit/init.gradle
@@ -15,7 +15,7 @@
  */
 
 import android.support.DacOptions
-
+import android.support.license.CheckExternalDependencyLicensesTask
 apply from: "${ext.supportRootFolder}/buildSrc/init.gradle"
 init.setSdkInLocalPropertiesFile()
 
@@ -42,6 +42,11 @@
 zipFlatfootDocsTask.dependsOn rootProject.tasks["generateDocs"]
 buildServerAnchorTask.dependsOn createDiffArchive
 buildServerAnchorTask.dependsOn createArchive
+rootProject.tasks.whenTaskAdded { task ->
+    if (CheckExternalDependencyLicensesTask.ROOT_TASK_NAME.equals(task.name)) {
+        buildServerAnchorTask.dependsOn task
+    }
+}
 
 subprojects {
     project.tasks.whenTaskAdded { task ->
diff --git a/app-toolkit/settings.gradle b/app-toolkit/settings.gradle
index 18176de..26bf742 100644
--- a/app-toolkit/settings.gradle
+++ b/app-toolkit/settings.gradle
@@ -96,6 +96,9 @@
 include ":persistence:db-framework"
 project(':persistence:db-framework').projectDir = new File(supportRoot, "persistence/db-framework")
 
+include ":room:guava"
+project(':room:guava').projectDir = new File(supportRoot, "room/guava")
+
 include ":room:testing"
 project(':room:testing').projectDir = new File(supportRoot, "room/testing")
 
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/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/init.gradle b/buildSrc/init.gradle
index b89bd92..38b41e8 100644
--- a/buildSrc/init.gradle
+++ b/buildSrc/init.gradle
@@ -17,6 +17,7 @@
 
 import android.support.DiffAndDocs
 import android.support.gmaven.GMavenVersionChecker
+import android.support.license.CheckExternalDependencyLicensesTask
 import com.android.build.gradle.internal.coverage.JacocoReportTask
 import com.android.build.gradle.internal.tasks.DeviceProviderInstrumentTestTask
 import org.gradle.api.logging.configuration.ShowStacktrace
@@ -158,7 +159,9 @@
 def configureBuildOnServer() {
     def buildOnServerTask = rootProject.tasks.create("buildOnServer")
     rootProject.tasks.whenTaskAdded { task ->
-        if ("createArchive".equals(task.name) || "distDocs".equals(task.name)) {
+        if ("createArchive".equals(task.name)
+                || "distDocs".equals(task.name)
+                || CheckExternalDependencyLicensesTask.ROOT_TASK_NAME.equals(task.name)) {
             buildOnServerTask.dependsOn task
         }
     }
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 170462d..2f64e5d 100644
--- a/buildSrc/src/main/kotlin/android/support/LibraryGroups.kt
+++ b/buildSrc/src/main/kotlin/android/support/LibraryGroups.kt
@@ -27,6 +27,5 @@
     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 1d091e1..cf5c647 100644
--- a/buildSrc/src/main/kotlin/android/support/LibraryVersions.kt
+++ b/buildSrc/src/main/kotlin/android/support/LibraryVersions.kt
@@ -23,12 +23,12 @@
     /**
      * Version code of the support library components.
      */
-    val SUPPORT_LIBRARY = Version("28.0.0-SNAPSHOT")
+    val SUPPORT_LIBRARY = Version("28.0.0-alpha1")
 
     /**
      * Version code for Room
      */
-    val ROOM = Version("1.1.0-alpha1")
+    val ROOM = Version("1.1.0-alpha2")
 
     /**
      * Version code for Lifecycle extensions (ProcessLifecycleOwner, Fragment support)
@@ -46,9 +46,9 @@
     val LIFECYCLES_VIEWMODEL = LIFECYCLES_EXT
 
     /**
-     * Version code for RecyclerView & Room paging
+     * Version code for Paging
      */
-    val PAGING = Version("1.0.0-alpha5")
+    val PAGING = Version("1.0.0-alpha6")
 
     private val LIFECYCLES = Version("1.1.0")
 
diff --git a/buildSrc/src/main/kotlin/android/support/SupportAndroidLibraryPlugin.kt b/buildSrc/src/main/kotlin/android/support/SupportAndroidLibraryPlugin.kt
index a9cb293..14e4669 100644
--- a/buildSrc/src/main/kotlin/android/support/SupportAndroidLibraryPlugin.kt
+++ b/buildSrc/src/main/kotlin/android/support/SupportAndroidLibraryPlugin.kt
@@ -17,6 +17,7 @@
 package android.support
 
 import android.support.SupportConfig.INSTRUMENTATION_RUNNER
+import android.support.license.CheckExternalDependencyLicensesTask
 import com.android.build.gradle.LibraryExtension
 import com.android.build.gradle.internal.dsl.LintOptions
 import com.android.build.gradle.tasks.GenerateBuildConfig
@@ -37,7 +38,7 @@
         val supportLibraryExtension = project.extensions.create("supportLibrary",
                 SupportLibraryExtension::class.java, project)
         apply(project, supportLibraryExtension)
-
+        CheckExternalDependencyLicensesTask.configure(project)
         val isCoreSupportLibrary = project.rootProject.name == "support"
 
         project.afterEvaluate {
@@ -46,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
@@ -131,7 +120,7 @@
 
         project.afterEvaluate {
             setUpLint(library.lintOptions, SupportConfig.getLintBaseline(project),
-                    (supportLibraryExtension.mavenVersion?.isSnapshot()) ?: true)
+                    (supportLibraryExtension.mavenVersion?.isFinalApi()) ?: false)
         }
 
         project.tasks.getByName("uploadArchives").dependsOn("lintRelease")
@@ -139,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")) {
@@ -149,7 +139,7 @@
     }
 }
 
-private fun setUpLint(lintOptions: LintOptions, baseline: File, snapshotVersion: Boolean) {
+private fun setUpLint(lintOptions: LintOptions, baseline: File, verifyTranslations: Boolean) {
     // Always lint check NewApi as fatal.
     lintOptions.isAbortOnError = true
     lintOptions.isIgnoreWarnings = true
@@ -169,15 +159,10 @@
 
     lintOptions.fatal("NewApi")
 
-    if (snapshotVersion) {
-        // Do not run missing translations checks on snapshot versions of the library.
-        lintOptions.disable("MissingTranslation")
-    } else {
+    if (verifyTranslations) {
         lintOptions.fatal("MissingTranslation")
-    }
-
-    if (System.getenv("GRADLE_PLUGIN_VERSION") != null) {
-        lintOptions.check("NewApi")
+    } else {
+        lintOptions.disable("MissingTranslation")
     }
 
     // Set baseline file for all legacy lint warnings.
diff --git a/buildSrc/src/main/kotlin/android/support/SupportAndroidTestAppPlugin.kt b/buildSrc/src/main/kotlin/android/support/SupportAndroidTestAppPlugin.kt
index 5bbda12..1604bbe 100644
--- a/buildSrc/src/main/kotlin/android/support/SupportAndroidTestAppPlugin.kt
+++ b/buildSrc/src/main/kotlin/android/support/SupportAndroidTestAppPlugin.kt
@@ -17,6 +17,7 @@
 package android.support
 
 import android.support.SupportConfig.INSTRUMENTATION_RUNNER
+import android.support.license.CheckExternalDependencyLicensesTask
 import com.android.build.gradle.AppExtension
 import net.ltgt.gradle.errorprone.ErrorProneBasePlugin
 import net.ltgt.gradle.errorprone.ErrorProneToolChain
@@ -33,7 +34,7 @@
     override fun apply(project: Project) {
         val testAppExtension = project.extensions.create("supportTestApp",
                 SupportAndroidTestAppExtension::class.java, project)
-
+        CheckExternalDependencyLicensesTask.configure(project)
         project.afterEvaluate {
             val application = project.extensions.findByType(AppExtension::class.java)
                     ?: throw Exception("Failed to find Android extension")
@@ -71,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/SupportJavaLibraryPlugin.kt b/buildSrc/src/main/kotlin/android/support/SupportJavaLibraryPlugin.kt
index cc2f985..f3651ab 100644
--- a/buildSrc/src/main/kotlin/android/support/SupportJavaLibraryPlugin.kt
+++ b/buildSrc/src/main/kotlin/android/support/SupportJavaLibraryPlugin.kt
@@ -16,6 +16,7 @@
 
 package android.support
 
+import android.support.license.CheckExternalDependencyLicensesTask
 import net.ltgt.gradle.errorprone.ErrorProneBasePlugin
 import net.ltgt.gradle.errorprone.ErrorProneToolChain
 import org.gradle.api.JavaVersion
@@ -49,9 +50,11 @@
 
         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) }
 
         setUpSourceJarTaskForJavaProject(project)
+        CheckExternalDependencyLicensesTask.configure(project)
     }
 }
diff --git a/buildSrc/src/main/kotlin/android/support/SupportKotlinLibraryPlugin.kt b/buildSrc/src/main/kotlin/android/support/SupportKotlinLibraryPlugin.kt
index d18d533..8651ef8 100644
--- a/buildSrc/src/main/kotlin/android/support/SupportKotlinLibraryPlugin.kt
+++ b/buildSrc/src/main/kotlin/android/support/SupportKotlinLibraryPlugin.kt
@@ -15,6 +15,7 @@
  */
 package android.support
 
+import android.support.license.CheckExternalDependencyLicensesTask
 import org.gradle.api.JavaVersion
 import org.gradle.api.Plugin
 import org.gradle.api.Project
@@ -31,5 +32,6 @@
         val convention = project.convention.getPlugin(JavaPluginConvention::class.java)
         convention.sourceCompatibility = JavaVersion.VERSION_1_8
         convention.targetCompatibility = JavaVersion.VERSION_1_8
+        CheckExternalDependencyLicensesTask.configure(project)
     }
 }
\ No newline at end of file
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/dependencies/Dependencies.kt b/buildSrc/src/main/kotlin/android/support/dependencies/Dependencies.kt
index f152892..0844832 100644
--- a/buildSrc/src/main/kotlin/android/support/dependencies/Dependencies.kt
+++ b/buildSrc/src/main/kotlin/android/support/dependencies/Dependencies.kt
@@ -19,7 +19,7 @@
 const val AUTO_COMMON = "com.google.auto:auto-common:0.6"
 const val ANTLR = "org.antlr:antlr4:4.5.3"
 const val APACHE_COMMONS_CODEC = "commons-codec:commons-codec:1.10"
-const val CONSTRAINT_LAYOUT = "com.android.support.constraint:constraint-layout:1.0.2"
+const val CONSTRAINT_LAYOUT = "com.android.support.constraint:constraint-layout:1.0.2@aar"
 const val DEXMAKER_MOCKITO = "com.linkedin.dexmaker:dexmaker-mockito:2.2.0"
 const val ESPRESSO_CONTRIB = "com.android.support.test.espresso:espresso-contrib:3.0.1"
 const val ESPRESSO_CORE = "com.android.support.test.espresso:espresso-core:3.0.1"
@@ -50,6 +50,12 @@
 
 // Support library dependencies needed for projects that compile against prebuilt versions
 // instead of source directly.
+// NOTE: _27 versions exist for modules that have opted-in to 27, and tests that depend on those
+// modules. Other projects may stick to older versions to avoid forcing users to update.
+private const val SUPPORT_VERSION_27 = "27.1.0"
+const val SUPPORT_RECYCLERVIEW_27 = "com.android.support:recyclerview-v7:$SUPPORT_VERSION_27"
+const val SUPPORT_APPCOMPAT_27 = "com.android.support:appcompat-v7:$SUPPORT_VERSION_27"
+
 private const val SUPPORT_VERSION = "26.1.0"
 const val SUPPORT_ANNOTATIONS = "com.android.support:support-annotations:$SUPPORT_VERSION"
 const val SUPPORT_APPCOMPAT = "com.android.support:appcompat-v7:$SUPPORT_VERSION"
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/kotlin/android/support/license/CheckExternalDependencyLicensesTask.kt b/buildSrc/src/main/kotlin/android/support/license/CheckExternalDependencyLicensesTask.kt
new file mode 100644
index 0000000..771f222
--- /dev/null
+++ b/buildSrc/src/main/kotlin/android/support/license/CheckExternalDependencyLicensesTask.kt
@@ -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 android.support.license
+
+import org.gradle.api.DefaultTask
+import org.gradle.api.GradleException
+import org.gradle.api.Project
+import org.gradle.api.artifacts.ExternalDependency
+import org.gradle.api.plugins.ExtraPropertiesExtension
+import org.gradle.api.tasks.TaskAction
+import java.io.File
+
+/**
+ * This task creates a configuration for the project that has all of its external dependencies
+ * and then ensures that those dependencies:
+ * a) come from prebuilts
+ * b) has a license file.
+ */
+open class CheckExternalDependencyLicensesTask : DefaultTask() {
+    @Suppress("unused")
+    @TaskAction
+    fun checkDependencies() {
+        val supportRoot = (project.rootProject.property("ext") as ExtraPropertiesExtension)
+                .get("supportRootFolder") as File
+        val prebuiltsRoot = File(supportRoot, "../../prebuilts").canonicalFile
+
+        val checkerConfig = project.configurations.getByName(CONFIG)
+
+        project
+                .configurations
+                .flatMap {
+                    it.allDependencies
+                            .filterIsInstance(ExternalDependency::class.java)
+                            .filterNot {
+                                it.group?.startsWith("com.android") == true
+                            }
+                            .filterNot {
+                                it.group?.startsWith("android.arch") == true
+                            }
+                }
+                .forEach {
+                    checkerConfig.dependencies.add(it)
+                }
+        val missingLicenses = checkerConfig.resolve().filter {
+            findLicenseFile(it.canonicalFile, prebuiltsRoot) == null
+        }
+        if (missingLicenses.isNotEmpty()) {
+            val suggestions = missingLicenses.joinToString("\n") {
+                "$it does not have a license file. It should probably live in " +
+                        "${it.parentFile.parentFile}"
+            }
+            throw GradleException("""
+                Any external library referenced in the support library
+                build must have a LICENSE or NOTICE file next to it in the prebuilts.
+                The following libraries are missing it:
+                $suggestions
+                """.trimIndent())
+        }
+    }
+
+    private fun findLicenseFile(dependency: File, prebuiltsRoot: File): File? {
+        if (!dependency.absolutePath.startsWith(prebuiltsRoot.absolutePath)) {
+            throw GradleException("prebuilts should come from prebuilts folder. $dependency is" +
+                    " not there")
+        }
+        fun recurse(folder: File): File? {
+            if (folder == prebuiltsRoot) {
+                return null
+            }
+            if (!folder.isDirectory) {
+                return recurse(folder.parentFile)
+            }
+
+            val found = folder.listFiles().firstOrNull {
+                it.name.toUpperCase().startsWith("NOTICE")
+                        || it.name.toUpperCase().startsWith("LICENSE")
+            }
+            return found ?: recurse(folder.parentFile)
+        }
+        return recurse(dependency)
+    }
+
+    companion object {
+        private const val CONFIG = "allExternalDependencies"
+        const val ROOT_TASK_NAME = "checkExternalLicenses"
+        private const val PER_PROJECT_TASK_NAME = ROOT_TASK_NAME
+        fun configure(project: Project) {
+            val task = project.tasks.create(PER_PROJECT_TASK_NAME,
+                    CheckExternalDependencyLicensesTask::class.java)
+            project.configurations.create(CONFIG)
+            val rootTask = project.rootProject.tasks.findByName(ROOT_TASK_NAME)
+                    ?: project.rootProject.tasks.create(ROOT_TASK_NAME)
+            rootTask.dependsOn(task)
+        }
+    }
+}
\ No newline at end of file
diff --git a/car/Android.mk b/car/Android.mk
index 6e9eb05..b15732f 100644
--- a/car/Android.mk
+++ b/car/Android.mk
@@ -21,6 +21,14 @@
 #       $(ANDROID_SUPPORT_CAR_TARGETS)
 #
 # in their makefiles to include the resources and their dependencies in their package.
+
+# Create a prebuilt library for android.car stubs. Implementation will be available as part of
+# system on automotive devices.
+include $(CLEAR_VARS)
+LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := \
+        prebuilt-android.car-stubs:car-stubs/android.car.jar
+include $(BUILD_MULTI_PREBUILT)
+
 include $(CLEAR_VARS)
 LOCAL_USE_AAPT2 := true
 LOCAL_MODULE := android-support-car
@@ -28,6 +36,8 @@
 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_STATIC_JAVA_LIBRARIES := \
+    prebuilt-android.car-stubs
 LOCAL_JAVA_LIBRARIES := \
     android-support-annotations
 LOCAL_SHARED_ANDROID_LIBRARIES := \
diff --git a/car/build.gradle b/car/build.gradle
index 163300d..819f0ad 100644
--- a/car/build.gradle
+++ b/car/build.gradle
@@ -23,6 +23,10 @@
     testImplementation(JUNIT)
     testImplementation(TEST_RUNNER)
     testImplementation(MOCKITO_CORE)
+
+    compileOnly fileTree(dir: 'car-stubs', include: ['android.car.jar'])
+    // androidTest uses android.car APIs to provide test utility.
+    androidTestCompileOnly fileTree(dir: 'car-stubs', include: ['android.car.jar'])
 }
 
 android {
diff --git a/car/car-stubs/LICENSE b/car/car-stubs/LICENSE
new file mode 100644
index 0000000..261eeb9
--- /dev/null
+++ b/car/car-stubs/LICENSE
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/car/car-stubs/README.android b/car/car-stubs/README.android
new file mode 100644
index 0000000..88b15b2
--- /dev/null
+++ b/car/car-stubs/README.android
@@ -0,0 +1,5 @@
+# stubs of android.car
+This library contains stubs generated for android.car.jar library.
+
+This library is intended to be compiled against only. Actual android.car library
+is expected to be available at runtime on automotive devices.
diff --git a/car/car-stubs/android.car.jar b/car/car-stubs/android.car.jar
new file mode 100644
index 0000000..2c8bf77
--- /dev/null
+++ b/car/car-stubs/android.car.jar
Binary files differ
diff --git a/car/res/layout/car_alert_dialog.xml b/car/res/layout/car_alert_dialog.xml
index 63dc70c..7b99a94 100644
--- a/car/res/layout/car_alert_dialog.xml
+++ b/car/res/layout/car_alert_dialog.xml
@@ -40,7 +40,7 @@
             android:id="@+id/title"
             android:layout_width="wrap_content"
             android:layout_height="@dimen/car_dialog_header_height"
-            android:textAppearance="@style/CarTitle2"
+            android:textAppearance="@style/TextAppearance.Car.Title2"
             android:gravity="center_vertical|start"
             android:maxLines="1"
             android:ellipsize="end"
@@ -50,7 +50,7 @@
             android:id="@+id/body"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:textAppearance="@style/CarBody2"
+            android:textAppearance="@style/TextAppearance.Car.Body2"
             android:visibility="gone" />
 
         <LinearLayout
diff --git a/car/res/layout/car_drawer_activity.xml b/car/res/layout/car_drawer_activity.xml
index 246f8de..802678b 100644
--- a/car/res/layout/car_drawer_activity.xml
+++ b/car/res/layout/car_drawer_activity.xml
@@ -51,6 +51,6 @@
             android:layout_height="@dimen/car_app_bar_height"
             android:layout_gravity="center_vertical"
             android:minHeight="@dimen/car_app_bar_height"
-            style="@style/CarToolbarTheme" />
+            style="@style/Widget.Car.Toolbar" />
     </android.support.design.widget.AppBarLayout>
 </android.support.design.widget.CoordinatorLayout>
diff --git a/car/res/layout/car_drawer_list_item_empty.xml b/car/res/layout/car_drawer_list_item_empty.xml
index c2e35ac..b8b8d74 100644
--- a/car/res/layout/car_drawer_list_item_empty.xml
+++ b/car/res/layout/car_drawer_list_item_empty.xml
@@ -41,5 +41,5 @@
         android:layout_height="wrap_content"
         android:layout_marginEnd="16dp"
         android:gravity="center"
-        style="@style/CarBody1" />
+        style="@style/TextAppearance.Car.Body1" />
 </LinearLayout>
diff --git a/car/res/layout/car_drawer_list_item_normal.xml b/car/res/layout/car_drawer_list_item_normal.xml
index 9136aae..86c0716 100644
--- a/car/res/layout/car_drawer_list_item_normal.xml
+++ b/car/res/layout/car_drawer_list_item_normal.xml
@@ -40,14 +40,14 @@
             android:layout_height="wrap_content"
             android:layout_marginBottom="@dimen/car_text_vertical_margin"
             android:maxLines="1"
-            style="@style/CarBody1" />
+            style="@style/TextAppearance.Car.Body1" />
         <TextView
             android:id="@+id/text"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:ellipsize="end"
             android:maxLines="1"
-            style="@style/CarBody2" />
+            style="@style/TextAppearance.Car.Body2" />
     </LinearLayout>
     <ImageView
         android:id="@+id/end_icon"
diff --git a/car/res/layout/car_drawer_list_item_small.xml b/car/res/layout/car_drawer_list_item_small.xml
index 2818eef..ac9932a 100644
--- a/car/res/layout/car_drawer_list_item_small.xml
+++ b/car/res/layout/car_drawer_list_item_small.xml
@@ -35,7 +35,7 @@
         android:layout_gravity="center_vertical"
         android:layout_marginBottom="@dimen/car_text_vertical_margin"
         android:maxLines="1"
-        style="@style/CarBody1" />
+        style="@style/TextAppearance.Car.Body1" />
     <ImageView
         android:id="@+id/end_icon"
         android:layout_width="@dimen/car_drawer_list_item_end_icon_size"
diff --git a/car/res/layout/car_list_dialog.xml b/car/res/layout/car_list_dialog.xml
new file mode 100644
index 0000000..cf36052
--- /dev/null
+++ b/car/res/layout/car_list_dialog.xml
@@ -0,0 +1,59 @@
+<?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.
+-->
+
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/container"
+    android:background="@android:color/transparent"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent" >
+
+    <!-- Note: the width is 0dp because ColumnCardView will automatically set a width based
+         on the number of columns it should take up. See ColumnCardView for more details. -->
+    <androidx.car.widget.ColumnCardView
+        android:layout_gravity="center"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/car_padding_4"
+        android:layout_marginBottom="@dimen/car_padding_4"
+        android:elevation="@dimen/car_dialog_elevation"
+        app:cardBackgroundColor="@color/car_card"
+        app:cardCornerRadius="@dimen/car_radius_3">
+
+        <!-- Hide the scrollbar for this PagedListView because it will be implemented by
+             @id/scrollbar. -->
+        <androidx.car.widget.PagedListView
+            android:id="@+id/list"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            app:gutter="none"
+            app:showPagedListViewDivider="true"
+            app:scrollBarEnabled="false" />
+    </androidx.car.widget.ColumnCardView>
+
+    <!-- Putting this as the last child for highest z-index. It is also clickable to reduce
+         the chance of clicks on the buttons accidentally dismissing the dialog. -->
+    <androidx.car.widget.PagedScrollBarView
+        android:id="@+id/scrollbar"
+        android:layout_width="@dimen/car_margin"
+        android:layout_height="match_parent"
+        android:layout_marginTop="@dimen/car_padding_4"
+        android:layout_marginBottom="@dimen/car_padding_4"
+        android:layout_gravity="start|top"
+        android:clickable="true"
+        android:visibility="invisible" />
+</FrameLayout>
diff --git a/car/res/layout/car_list_item_text_content.xml b/car/res/layout/car_list_item_text_content.xml
index d560ffe..943c489 100644
--- a/car/res/layout/car_list_item_text_content.xml
+++ b/car/res/layout/car_list_item_text_content.xml
@@ -19,7 +19,7 @@
     android:id="@+id/container"
     android:layout_width="wrap_content"
     android:layout_height="match_parent"
-    android:background="@drawable/car_card_ripple_background">
+    android:foreground="@drawable/car_card_ripple_background">
     <!-- Primary Action. -->
     <ImageView
         android:id="@+id/primary_icon"
diff --git a/car/res/layout/car_toolbar.xml b/car/res/layout/car_toolbar.xml
index 88f05e3..9880d21 100644
--- a/car/res/layout/car_toolbar.xml
+++ b/car/res/layout/car_toolbar.xml
@@ -22,5 +22,5 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_gravity="center_vertical"
-        style="@style/CarToolbarTheme" />
+        style="@style/Widget.Car.Toolbar" />
 </FrameLayout>
diff --git a/car/res/layout/lock_out_message.xml b/car/res/layout/lock_out_message.xml
index 218d79e..220e1f3 100644
--- a/car/res/layout/lock_out_message.xml
+++ b/car/res/layout/lock_out_message.xml
@@ -38,7 +38,7 @@
         android:id="@+id/lock_out_text"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:textAppearance="@style/CarBody1"
+        android:textAppearance="@style/TextAppearance.Car.Body1"
         android:layout_alignStart="@id/lock_out_drawable"
         android:layout_alignEnd="@id/lock_out_drawable"
         android:layout_alignTop="@id/lock_out_drawable"
diff --git a/car/res/values-af/strings.xml b/car/res/values-af/strings.xml
new file mode 100644
index 0000000..f307fc7
--- /dev/null
+++ b/car/res/values-af/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Konsentreer op die pad"</string>
+</resources>
diff --git a/car/res/values-am/strings.xml b/car/res/values-am/strings.xml
new file mode 100644
index 0000000..30ae48e
--- /dev/null
+++ b/car/res/values-am/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"መንገዱ ላይ ያተኩሩ"</string>
+</resources>
diff --git a/car/res/values-ar/strings.xml b/car/res/values-ar/strings.xml
new file mode 100644
index 0000000..e970ed9
--- /dev/null
+++ b/car/res/values-ar/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"ركِّز في الطريق"</string>
+</resources>
diff --git a/car/res/values-az/strings.xml b/car/res/values-az/strings.xml
new file mode 100644
index 0000000..e813849
--- /dev/null
+++ b/car/res/values-az/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Diqqətinizi yola yönəldin"</string>
+</resources>
diff --git a/car/res/values-b+sr+Latn/strings.xml b/car/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..a83a82c
--- /dev/null
+++ b/car/res/values-b+sr+Latn/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Fokusirajte se na put"</string>
+</resources>
diff --git a/car/res/values-be/strings.xml b/car/res/values-be/strings.xml
new file mode 100644
index 0000000..80912e4
--- /dev/null
+++ b/car/res/values-be/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Увага на дарогу"</string>
+</resources>
diff --git a/car/res/values-bg/strings.xml b/car/res/values-bg/strings.xml
new file mode 100644
index 0000000..dd5811f
--- /dev/null
+++ b/car/res/values-bg/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Съсредоточете се върху пътя"</string>
+</resources>
diff --git a/car/res/values-bn/strings.xml b/car/res/values-bn/strings.xml
new file mode 100644
index 0000000..fcf0165
--- /dev/null
+++ b/car/res/values-bn/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"মনোযোগ দিয়ে গাড়ি চালান"</string>
+</resources>
diff --git a/car/res/values-bs/strings.xml b/car/res/values-bs/strings.xml
new file mode 100644
index 0000000..99e655e
--- /dev/null
+++ b/car/res/values-bs/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Fokusirajte se na cestu"</string>
+</resources>
diff --git a/car/res/values-ca/strings.xml b/car/res/values-ca/strings.xml
new file mode 100644
index 0000000..758f6e7
--- /dev/null
+++ b/car/res/values-ca/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Concentra\'t en la carretera"</string>
+</resources>
diff --git a/car/res/values-cs/strings.xml b/car/res/values-cs/strings.xml
new file mode 100644
index 0000000..27090ef
--- /dev/null
+++ b/car/res/values-cs/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Soustřeďte se na silnici"</string>
+</resources>
diff --git a/car/res/values-da/strings.xml b/car/res/values-da/strings.xml
new file mode 100644
index 0000000..96cc062
--- /dev/null
+++ b/car/res/values-da/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Hold øjnene på vejen"</string>
+</resources>
diff --git a/car/res/values-de/strings.xml b/car/res/values-de/strings.xml
new file mode 100644
index 0000000..ee289ac
--- /dev/null
+++ b/car/res/values-de/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Achte auf den Verkehr"</string>
+</resources>
diff --git a/car/res/values-el/strings.xml b/car/res/values-el/strings.xml
new file mode 100644
index 0000000..cf8ab8f
--- /dev/null
+++ b/car/res/values-el/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Επικεντρωθείτε στον δρόμο"</string>
+</resources>
diff --git a/car/res/values-en-rAU/strings.xml b/car/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000..8cc3360
--- /dev/null
+++ b/car/res/values-en-rAU/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Focus on the road"</string>
+</resources>
diff --git a/car/res/values-en-rCA/strings.xml b/car/res/values-en-rCA/strings.xml
new file mode 100644
index 0000000..8cc3360
--- /dev/null
+++ b/car/res/values-en-rCA/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Focus on the road"</string>
+</resources>
diff --git a/car/res/values-en-rGB/strings.xml b/car/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..8cc3360
--- /dev/null
+++ b/car/res/values-en-rGB/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Focus on the road"</string>
+</resources>
diff --git a/car/res/values-en-rIN/strings.xml b/car/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..8cc3360
--- /dev/null
+++ b/car/res/values-en-rIN/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Focus on the road"</string>
+</resources>
diff --git a/car/res/values-en-rXC/strings.xml b/car/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000..c11c1cb
--- /dev/null
+++ b/car/res/values-en-rXC/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‎‎‎‎‏‎‎‏‏‏‎‎‏‎‏‎‏‏‏‏‏‎‎‎‏‎‏‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‎‏‎‎‏‏‏‏‎Focus on the road‎‏‎‎‏‎"</string>
+</resources>
diff --git a/car/res/values-es-rUS/strings.xml b/car/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..6ac20d7
--- /dev/null
+++ b/car/res/values-es-rUS/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Concéntrate en el camino"</string>
+</resources>
diff --git a/car/res/values-es/strings.xml b/car/res/values-es/strings.xml
new file mode 100644
index 0000000..09a493f
--- /dev/null
+++ b/car/res/values-es/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Céntrate en la carretera"</string>
+</resources>
diff --git a/car/res/values-et/strings.xml b/car/res/values-et/strings.xml
new file mode 100644
index 0000000..66f6e48
--- /dev/null
+++ b/car/res/values-et/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Keskenduge teele"</string>
+</resources>
diff --git a/car/res/values-eu/strings.xml b/car/res/values-eu/strings.xml
new file mode 100644
index 0000000..3773f71
--- /dev/null
+++ b/car/res/values-eu/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Jarri arreta errepidean"</string>
+</resources>
diff --git a/car/res/values-fa/strings.xml b/car/res/values-fa/strings.xml
new file mode 100644
index 0000000..8668d6b
--- /dev/null
+++ b/car/res/values-fa/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"روی جاده تمرکز داشته باشید"</string>
+</resources>
diff --git a/car/res/values-fi/strings.xml b/car/res/values-fi/strings.xml
new file mode 100644
index 0000000..e93cb9c
--- /dev/null
+++ b/car/res/values-fi/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Pidä katse tiessä"</string>
+</resources>
diff --git a/car/res/values-fr-rCA/strings.xml b/car/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..f32315b
--- /dev/null
+++ b/car/res/values-fr-rCA/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Concentrez-vous sur la route"</string>
+</resources>
diff --git a/car/res/values-fr/strings.xml b/car/res/values-fr/strings.xml
new file mode 100644
index 0000000..f32315b
--- /dev/null
+++ b/car/res/values-fr/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Concentrez-vous sur la route"</string>
+</resources>
diff --git a/car/res/values-gl/strings.xml b/car/res/values-gl/strings.xml
new file mode 100644
index 0000000..42bc515
--- /dev/null
+++ b/car/res/values-gl/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Céntrate na estrada"</string>
+</resources>
diff --git a/car/res/values-gu/strings.xml b/car/res/values-gu/strings.xml
new file mode 100644
index 0000000..f215ec2
--- /dev/null
+++ b/car/res/values-gu/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"રસ્તા પર ફોકસ કરો"</string>
+</resources>
diff --git a/car/res/values-h1752dp/dimens.xml b/car/res/values-h1752dp/dimens.xml
index f04ed45..ea5ebd6 100644
--- a/car/res/values-h1752dp/dimens.xml
+++ b/car/res/values-h1752dp/dimens.xml
@@ -21,6 +21,7 @@
     <dimen name="car_headline2_size">50sp</dimen>
     <dimen name="car_body1_size">40sp</dimen>
     <dimen name="car_body2_size">32sp</dimen>
+    <dimen name="car_label1_size">32sp</dimen>
     <dimen name="car_action1_size">32sp</dimen>
 
     <!-- Icons and Buttons -->
diff --git a/car/res/values-h668dp/dimens.xml b/car/res/values-h668dp/dimens.xml
index 9a2b5c3..4c7aae6 100644
--- a/car/res/values-h668dp/dimens.xml
+++ b/car/res/values-h668dp/dimens.xml
@@ -14,6 +14,16 @@
 limitations under the License.
 -->
 <resources>
+    <!-- Paddings -->
+    <dimen name="car_padding_2">16dp</dimen>
+    <dimen name="car_padding_3">28dp</dimen>
+    <dimen name="car_padding_4">32dp</dimen>
+    <dimen name="car_padding_5">64dp</dimen>
+    <dimen name="car_padding_6">96dp</dimen>
+
+    <!-- Type Sizings -->
+    <dimen name="car_headline2_size">36sp</dimen>
+
     <!-- Car Component Dimensions -->
     <!-- Application Bar -->
     <dimen name="car_app_bar_height">96dp</dimen>
diff --git a/car/res/values-hi/strings.xml b/car/res/values-hi/strings.xml
new file mode 100644
index 0000000..53f8a8d
--- /dev/null
+++ b/car/res/values-hi/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"सड़क पर ध्यान दें"</string>
+</resources>
diff --git a/car/res/values-hr/strings.xml b/car/res/values-hr/strings.xml
new file mode 100644
index 0000000..0a08dcc
--- /dev/null
+++ b/car/res/values-hr/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Usredotočite se na cestu"</string>
+</resources>
diff --git a/car/res/values-hu/strings.xml b/car/res/values-hu/strings.xml
new file mode 100644
index 0000000..3618719
--- /dev/null
+++ b/car/res/values-hu/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Figyeljen az útra"</string>
+</resources>
diff --git a/car/res/values-hy/strings.xml b/car/res/values-hy/strings.xml
new file mode 100644
index 0000000..3a85b41
--- /dev/null
+++ b/car/res/values-hy/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Հետևեք ճանապարհին"</string>
+</resources>
diff --git a/car/res/values-in/strings.xml b/car/res/values-in/strings.xml
new file mode 100644
index 0000000..81daf29
--- /dev/null
+++ b/car/res/values-in/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Konsentrasi saat mengemudi"</string>
+</resources>
diff --git a/car/res/values-is/strings.xml b/car/res/values-is/strings.xml
new file mode 100644
index 0000000..4b5d26d
--- /dev/null
+++ b/car/res/values-is/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Einbeittu þér að akstrinum"</string>
+</resources>
diff --git a/car/res/values-it/strings.xml b/car/res/values-it/strings.xml
new file mode 100644
index 0000000..b395409
--- /dev/null
+++ b/car/res/values-it/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Concentrati sulla strada"</string>
+</resources>
diff --git a/car/res/values-iw/strings.xml b/car/res/values-iw/strings.xml
new file mode 100644
index 0000000..ab92be5
--- /dev/null
+++ b/car/res/values-iw/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"עליך להתמקד בכביש"</string>
+</resources>
diff --git a/car/res/values-ja/strings.xml b/car/res/values-ja/strings.xml
new file mode 100644
index 0000000..89fce3b
--- /dev/null
+++ b/car/res/values-ja/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"運転に集中してください"</string>
+</resources>
diff --git a/car/res/values-ka/strings.xml b/car/res/values-ka/strings.xml
new file mode 100644
index 0000000..e3f2e07
--- /dev/null
+++ b/car/res/values-ka/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"კონცენტრირდით გზაზე"</string>
+</resources>
diff --git a/car/res/values-kk/strings.xml b/car/res/values-kk/strings.xml
new file mode 100644
index 0000000..bbccd56
--- /dev/null
+++ b/car/res/values-kk/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Жолға назар аударыңыз"</string>
+</resources>
diff --git a/car/res/values-km/strings.xml b/car/res/values-km/strings.xml
new file mode 100644
index 0000000..50fe2db
--- /dev/null
+++ b/car/res/values-km/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"ផ្តោតលើ​ការបើកបរ"</string>
+</resources>
diff --git a/car/res/values-kn/strings.xml b/car/res/values-kn/strings.xml
new file mode 100644
index 0000000..6562ee2
--- /dev/null
+++ b/car/res/values-kn/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"ರಸ್ತೆಯ ಮೇಲೆ ಗಮನಹರಿಸಿ"</string>
+</resources>
diff --git a/car/res/values-ko/strings.xml b/car/res/values-ko/strings.xml
new file mode 100644
index 0000000..ac5865a
--- /dev/null
+++ b/car/res/values-ko/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"도로 상황에 집중하세요."</string>
+</resources>
diff --git a/car/res/values-ky/strings.xml b/car/res/values-ky/strings.xml
new file mode 100644
index 0000000..3640239
--- /dev/null
+++ b/car/res/values-ky/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Жолго көңүл буруңуз"</string>
+</resources>
diff --git a/car/res/values-lo/strings.xml b/car/res/values-lo/strings.xml
new file mode 100644
index 0000000..4af3152
--- /dev/null
+++ b/car/res/values-lo/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"ຕັ້ງໃຈຂັບລົດ"</string>
+</resources>
diff --git a/car/res/values-lt/strings.xml b/car/res/values-lt/strings.xml
new file mode 100644
index 0000000..685bbe5
--- /dev/null
+++ b/car/res/values-lt/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Sutelkite dėmesį į kelią"</string>
+</resources>
diff --git a/car/res/values-lv/strings.xml b/car/res/values-lv/strings.xml
new file mode 100644
index 0000000..417d331
--- /dev/null
+++ b/car/res/values-lv/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Pievērsieties autovadīšanai"</string>
+</resources>
diff --git a/car/res/values-mk/strings.xml b/car/res/values-mk/strings.xml
new file mode 100644
index 0000000..7377299
--- /dev/null
+++ b/car/res/values-mk/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Фокусирајте се на патот"</string>
+</resources>
diff --git a/car/res/values-ml/strings.xml b/car/res/values-ml/strings.xml
new file mode 100644
index 0000000..d5ad91d
--- /dev/null
+++ b/car/res/values-ml/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"റോഡിൽ ശ്രദ്ധിക്കുക"</string>
+</resources>
diff --git a/car/res/values-mn/strings.xml b/car/res/values-mn/strings.xml
new file mode 100644
index 0000000..4b249a4
--- /dev/null
+++ b/car/res/values-mn/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Зам дээр төвлөрөх"</string>
+</resources>
diff --git a/car/res/values-mr/strings.xml b/car/res/values-mr/strings.xml
new file mode 100644
index 0000000..c79f3f3
--- /dev/null
+++ b/car/res/values-mr/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"रस्त्यावर फोकस करा"</string>
+</resources>
diff --git a/car/res/values-ms/strings.xml b/car/res/values-ms/strings.xml
new file mode 100644
index 0000000..d209113
--- /dev/null
+++ b/car/res/values-ms/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Beri tumpuan pada jalan raya"</string>
+</resources>
diff --git a/car/res/values-my/strings.xml b/car/res/values-my/strings.xml
new file mode 100644
index 0000000..438729a
--- /dev/null
+++ b/car/res/values-my/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"လမ်းကို အာရုံစိုက်ရန်"</string>
+</resources>
diff --git a/car/res/values-nb/strings.xml b/car/res/values-nb/strings.xml
new file mode 100644
index 0000000..eb3a144
--- /dev/null
+++ b/car/res/values-nb/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Fokuser på veien"</string>
+</resources>
diff --git a/car/res/values-ne/strings.xml b/car/res/values-ne/strings.xml
new file mode 100644
index 0000000..d066c0b
--- /dev/null
+++ b/car/res/values-ne/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"सडकमा ध्यान केन्द्रित गर्नु…"</string>
+</resources>
diff --git a/car/res/values-night/colors.xml b/car/res/values-night/colors.xml
index 3bf658f..c237b19 100644
--- a/car/res/values-night/colors.xml
+++ b/car/res/values-night/colors.xml
@@ -25,6 +25,7 @@
     <color name="car_body2">@color/car_body2_light</color>
     <color name="car_body3">@color/car_body3_light</color>
     <color name="car_body4">@color/car_body4_light</color>
+    <color name="car_label1">@color/car_label1_light</color>
     <color name="car_action1">@color/car_action1_light</color>
 
     <color name="car_tint">@color/car_tint_light</color>
diff --git a/car/res/values-nl/strings.xml b/car/res/values-nl/strings.xml
new file mode 100644
index 0000000..7fcb11e
--- /dev/null
+++ b/car/res/values-nl/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Houd je aandacht op de weg"</string>
+</resources>
diff --git a/car/res/values-pa/strings.xml b/car/res/values-pa/strings.xml
new file mode 100644
index 0000000..137bd2a
--- /dev/null
+++ b/car/res/values-pa/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"ਸੜਕ \'ਤੇ ਧਿਆਨ ਦਿਓ"</string>
+</resources>
diff --git a/car/res/values-pl/strings.xml b/car/res/values-pl/strings.xml
new file mode 100644
index 0000000..c5aa323
--- /dev/null
+++ b/car/res/values-pl/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Skup się na drodze"</string>
+</resources>
diff --git a/car/res/values-pt-rBR/strings.xml b/car/res/values-pt-rBR/strings.xml
new file mode 100644
index 0000000..a6c515a
--- /dev/null
+++ b/car/res/values-pt-rBR/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Foco na estrada"</string>
+</resources>
diff --git a/car/res/values-pt-rPT/strings.xml b/car/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..2338efe
--- /dev/null
+++ b/car/res/values-pt-rPT/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Concentre-se na estrada."</string>
+</resources>
diff --git a/car/res/values-pt/strings.xml b/car/res/values-pt/strings.xml
new file mode 100644
index 0000000..a6c515a
--- /dev/null
+++ b/car/res/values-pt/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Foco na estrada"</string>
+</resources>
diff --git a/car/res/values-ro/strings.xml b/car/res/values-ro/strings.xml
new file mode 100644
index 0000000..20cc3e7
--- /dev/null
+++ b/car/res/values-ro/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Concentrați-vă asupra drumului"</string>
+</resources>
diff --git a/car/res/values-ru/strings.xml b/car/res/values-ru/strings.xml
new file mode 100644
index 0000000..198f7fa
--- /dev/null
+++ b/car/res/values-ru/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Следите за дорогой"</string>
+</resources>
diff --git a/car/res/values-si/strings.xml b/car/res/values-si/strings.xml
new file mode 100644
index 0000000..530c12a
--- /dev/null
+++ b/car/res/values-si/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"මාර්ගයට අවධානය යොමු කරන්න"</string>
+</resources>
diff --git a/car/res/values-sk/strings.xml b/car/res/values-sk/strings.xml
new file mode 100644
index 0000000..a959d09
--- /dev/null
+++ b/car/res/values-sk/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Sústreďte sa na cestu"</string>
+</resources>
diff --git a/car/res/values-sl/strings.xml b/car/res/values-sl/strings.xml
new file mode 100644
index 0000000..c0a8164
--- /dev/null
+++ b/car/res/values-sl/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Glejte na cesto"</string>
+</resources>
diff --git a/car/res/values-sq/strings.xml b/car/res/values-sq/strings.xml
new file mode 100644
index 0000000..c8c91ef
--- /dev/null
+++ b/car/res/values-sq/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Përqendrohu te rruga"</string>
+</resources>
diff --git a/car/res/values-sr/strings.xml b/car/res/values-sr/strings.xml
new file mode 100644
index 0000000..d7a6b85
--- /dev/null
+++ b/car/res/values-sr/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Фокусирајте се на пут"</string>
+</resources>
diff --git a/car/res/values-sv/strings.xml b/car/res/values-sv/strings.xml
new file mode 100644
index 0000000..3798509
--- /dev/null
+++ b/car/res/values-sv/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Fokusera på körningen"</string>
+</resources>
diff --git a/car/res/values-sw/strings.xml b/car/res/values-sw/strings.xml
new file mode 100644
index 0000000..a5b76c7
--- /dev/null
+++ b/car/res/values-sw/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Tia makini barabarani"</string>
+</resources>
diff --git a/car/res/values-ta/strings.xml b/car/res/values-ta/strings.xml
new file mode 100644
index 0000000..e97f385
--- /dev/null
+++ b/car/res/values-ta/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"வாகனம் ஓட்டும்போது கவனம் தேவை"</string>
+</resources>
diff --git a/car/res/values-te/strings.xml b/car/res/values-te/strings.xml
new file mode 100644
index 0000000..9079a09
--- /dev/null
+++ b/car/res/values-te/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"రహదారిపై దృష్టి ఉంచండి"</string>
+</resources>
diff --git a/car/res/values-th/strings.xml b/car/res/values-th/strings.xml
new file mode 100644
index 0000000..3ba0d6b
--- /dev/null
+++ b/car/res/values-th/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"จดจ่อกับถนน"</string>
+</resources>
diff --git a/car/res/values-tl/strings.xml b/car/res/values-tl/strings.xml
new file mode 100644
index 0000000..395e555
--- /dev/null
+++ b/car/res/values-tl/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Tumuon sa kalsada"</string>
+</resources>
diff --git a/car/res/values-tr/strings.xml b/car/res/values-tr/strings.xml
new file mode 100644
index 0000000..a0f0b22
--- /dev/null
+++ b/car/res/values-tr/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Dikkatinizi yola verin"</string>
+</resources>
diff --git a/car/res/values-uk/strings.xml b/car/res/values-uk/strings.xml
new file mode 100644
index 0000000..2657348
--- /dev/null
+++ b/car/res/values-uk/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Зосередьтеся на дорозі"</string>
+</resources>
diff --git a/car/res/values-ur/strings.xml b/car/res/values-ur/strings.xml
new file mode 100644
index 0000000..60c578c
--- /dev/null
+++ b/car/res/values-ur/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"سڑک پر توجہ مرکوز کریں"</string>
+</resources>
diff --git a/car/res/values-uz/strings.xml b/car/res/values-uz/strings.xml
new file mode 100644
index 0000000..bdaba48
--- /dev/null
+++ b/car/res/values-uz/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Diqqatingizni yo‘lga qarating"</string>
+</resources>
diff --git a/car/res/values-vi/strings.xml b/car/res/values-vi/strings.xml
new file mode 100644
index 0000000..37457d4
--- /dev/null
+++ b/car/res/values-vi/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Tập trung vào đường đi"</string>
+</resources>
diff --git a/car/res/values-zh-rCN/strings.xml b/car/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..ec0c3c4
--- /dev/null
+++ b/car/res/values-zh-rCN/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"请专心驾驶"</string>
+</resources>
diff --git a/car/res/values-zh-rHK/strings.xml b/car/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..61102cc
--- /dev/null
+++ b/car/res/values-zh-rHK/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"請專心駕駛"</string>
+</resources>
diff --git a/car/res/values-zh-rTW/strings.xml b/car/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..61102cc
--- /dev/null
+++ b/car/res/values-zh-rTW/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"請專心駕駛"</string>
+</resources>
diff --git a/car/res/values-zu/strings.xml b/car/res/values-zu/strings.xml
new file mode 100644
index 0000000..bdf7337
--- /dev/null
+++ b/car/res/values-zu/strings.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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Gxila emgwaqweni"</string>
+</resources>
diff --git a/car/res/values/attrs.xml b/car/res/values/attrs.xml
index 8b32b24..0559218 100644
--- a/car/res/values/attrs.xml
+++ b/car/res/values/attrs.xml
@@ -54,7 +54,9 @@
              within this value. If this value is not explicitly set, the scrollbar centers itself
              within the car_margin value. -->
         <attr name="scrollBarContainerWidth" format="dimension" />
-        <!-- Whether or not to show a diving line between each item of the list. -->
+        <!-- Whether or not to show a vertical diving line between each item of the list. Divider
+             after the last item (LinearLayoutManager) or row (GridLayoutManager) will not be shown
+             but there will be an offset for divider space. -->
         <attr name="showPagedListViewDivider" format="boolean" />
         <!-- An optional id that specifies a child View whose starting edge will be used to
              determine the start position of the dividing line. -->
@@ -68,7 +70,8 @@
         <!-- The width of the margin on the right side of the list.
              Deprecated: use gutter instead. If gutter is specified, this value is ignored.-->
         <attr name="listEndMargin" format="dimension" />
-        <!-- An optional spacing between items in the list -->
+        <!-- An optional vertical spacing between items in the list. In GridLayoutManager items in
+             the last row would still have spacing at bottom. -->
         <attr name="itemSpacing" format="dimension" />
         <!-- The icon to be used for the up button of the scroll bar. -->
         <attr name="upButtonIcon" format="reference" />
diff --git a/car/res/values/colors.xml b/car/res/values/colors.xml
index 5ace082..c7a4598 100644
--- a/car/res/values/colors.xml
+++ b/car/res/values/colors.xml
@@ -99,6 +99,10 @@
     <color name="car_body4_dark">@android:color/black</color>
     <color name="car_body4">@color/car_body4_dark</color>
 
+    <color name="car_label1_light">@color/car_grey_50</color>
+    <color name="car_label1_dark">@color/car_grey_900</color>
+    <color name="car_label1">@color/car_label1_dark</color>
+
     <color name="car_action1_light">@color/car_grey_900</color>
     <color name="car_action1_dark">@color/car_grey_50</color>
     <color name="car_action1">@color/car_action1_dark</color>
diff --git a/car/res/values/dimens.xml b/car/res/values/dimens.xml
index 013b578..8312800 100644
--- a/car/res/values/dimens.xml
+++ b/car/res/values/dimens.xml
@@ -34,11 +34,13 @@
     <dimen name="car_keyline_1_keyline_3_diff">88dp</dimen>
 
     <!-- Paddings -->
-    <dimen name="car_padding_1">4dp</dimen>
-    <dimen name="car_padding_2">10dp</dimen>
+    <dimen name="car_padding_0">4dp</dimen>
+    <dimen name="car_padding_1">10dp</dimen>
+    <dimen name="car_padding_2">12dp</dimen>
     <dimen name="car_padding_3">16dp</dimen>
-    <dimen name="car_padding_4">28dp</dimen>
-    <dimen name="car_padding_5">32dp</dimen>
+    <dimen name="car_padding_4">20dp</dimen>
+    <dimen name="car_padding_5">40dp</dimen>
+    <dimen name="car_padding_6">64dp</dimen>
 
     <!-- Radii -->
     <dimen name="car_radius_1">4dp</dimen>
@@ -51,7 +53,7 @@
     <dimen name="car_title_size">32sp</dimen>
     <dimen name="car_title2_size">32sp</dimen>
     <dimen name="car_headline1_size">45sp</dimen>
-    <dimen name="car_headline2_size">36sp</dimen>
+    <dimen name="car_headline2_size">32sp</dimen>
     <dimen name="car_headline3_size">24sp</dimen>
     <dimen name="car_headline4_size">20sp</dimen>
     <dimen name="car_body1_size">32sp</dimen>
@@ -59,6 +61,7 @@
     <dimen name="car_body3_size">16sp</dimen>
     <dimen name="car_body4_size">14sp</dimen>
     <dimen name="car_body5_size">18sp</dimen>
+    <dimen name="car_label1_size">26sp</dimen>
     <dimen name="car_action1_size">26sp</dimen>
 
     <!-- Icons and Buttons -->
diff --git a/car/res/values/styles.xml b/car/res/values/styles.xml
index 47ced9b..b67a512 100644
--- a/car/res/values/styles.xml
+++ b/car/res/values/styles.xml
@@ -14,51 +14,65 @@
 limitations under the License.
 -->
 <resources>
+    <style name="TextAppearance.Car" parent="TextAppearance.AppCompat" />
+
     <!-- The styling for title text. The color of this text changes based on day/night mode. -->
-    <style name="CarTitle">
+    <style name="TextAppearance.Car.Title">
+        <item name="android:fontFamily">sans-serif-medium</item>
         <item name="android:textStyle">normal</item>
         <item name="android:textSize">@dimen/car_title_size</item>
         <item name="android:textColor">@color/car_title</item>
     </style>
 
     <!-- Title text that is permanently a dark color. -->
-    <style name="CarTitle.Dark">
+    <style name="TextAppearance.Car.Title.Dark">
         <item name="android:textColor">@color/car_title_dark</item>
     </style>
 
     <!-- Title text that is permanently a light color. -->
-    <style name="CarTitle.Light">
+    <style name="TextAppearance.Car.Title.Light">
         <item name="android:textColor">@color/car_title_light</item>
     </style>
 
     <!-- The styling for title2 text. The color of this text changes based on day/night mode. -->
-    <style name="CarTitle2">
+    <style name="TextAppearance.Car.Title2">
+        <item name="android:fontFamily">sans-serif-medium</item>
         <item name="android:textStyle">normal</item>
         <item name="android:textSize">@dimen/car_title2_size</item>
         <item name="android:textColor">@color/car_title2</item>
     </style>
 
     <!-- Title2 text that is permanently a dark color. -->
-    <style name="CarTitle2.Dark">
+    <style name="TextAppearance.Car.Title2.Dark">
         <item name="android:textColor">@color/car_title2_dark</item>
     </style>
 
     <!-- Title2 text that is permanently a light color. -->
-    <style name="CarTitle2.Light">
+    <style name="TextAppearance.Car.Title2.Light">
         <item name="android:textColor">@color/car_title2_light</item>
     </style>
 
     <!-- The styling for the main headline text. The color of this text changes based on the
          day/night mode. -->
-    <style name="CarHeadline1">
+    <style name="TextAppearance.Car.Headline1">
         <item name="android:textStyle">normal</item>
         <item name="android:textSize">@dimen/car_headline1_size</item>
         <item name="android:textColor">@color/car_headline1</item>
     </style>
 
+    <!-- Title2 text that is permanently a light color. -->
+    <style name="TextAppearance.Car.Headline1.Light">
+        <item name="android:textColor">@color/car_headline1_light</item>
+    </style>
+
+    <!-- Title2 text that is permanently a dark color. -->
+    <style name="TextAppearance.Car.Headline1.Dark">
+        <item name="android:textColor">@color/car_headline1_dark</item>
+    </style>
+
     <!-- The styling for a sub-headline text. The color of this text changes based on the
          day/night mode. -->
-    <style name="CarHeadline2">
+    <style name="TextAppearance.Car.Headline2">
         <item name="android:textStyle">normal</item>
         <item name="android:textSize">@dimen/car_headline2_size</item>
         <item name="android:textColor">@color/car_headline2</item>
@@ -66,7 +80,7 @@
 
     <!-- The styling for a smaller alternate headline text. The color of this text changes based on
          the day/night mode. -->
-    <style name="CarHeadline3">
+    <style name="TextAppearance.Car.Headline3">
         <item name="android:textStyle">normal</item>
         <item name="android:textSize">@dimen/car_headline3_size</item>
         <item name="android:textColor">@color/car_headline3</item>
@@ -74,22 +88,39 @@
 
     <!-- The styling for the smallest headline text. The color of this text changes based on the
          day/night mode. -->
-    <style name="CarHeadline4">
+    <style name="TextAppearance.Car.Headline4">
         <item name="android:textStyle">normal</item>
         <item name="android:textSize">@dimen/car_headline4_size</item>
         <item name="android:textColor">@color/car_headline4</item>
     </style>
 
+    <!-- The styling for label text. The color of this text changes based on the day/night mode. -->
+    <style name="TextAppearance.Car.Label1">
+        <item name="android:textStyle">normal</item>
+        <item name="android:textSize">@dimen/car_label1_size</item>
+        <item name="android:textColor">@color/car_label1</item>
+    </style>
+
     <!-- The styling for body text. The color of this text changes based on the day/night mode. -->
-    <style name="CarBody1">
+    <style name="TextAppearance.Car.Body1">
         <item name="android:textStyle">normal</item>
         <item name="android:textSize">@dimen/car_body1_size</item>
         <item name="android:textColor">@color/car_body1</item>
     </style>
 
+    <!-- Title2 text that is permanently a light color. -->
+    <style name="TextAppearance.Car.Body1.Light">
+        <item name="android:textColor">@color/car_body1_light</item>
+    </style>
+
+    <!-- Title2 text that is permanently a dark color. -->
+    <style name="TextAppearance.Car.Body1.Dark">
+        <item name="android:textColor">@color/car_body2_dark</item>
+    </style>
+
     <!-- An alternate styling for body text that is both a different color and size than
          CarBody1. -->
-    <style name="CarBody2">
+    <style name="TextAppearance.Car.Body2">
         <item name="android:textStyle">normal</item>
         <item name="android:textSize">@dimen/car_body2_size</item>
         <item name="android:textColor">@color/car_body2</item>
@@ -97,7 +128,7 @@
 
     <!-- A smaller styling for body text. The color of this text changes based on the day/night
          mode. -->
-    <style name="CarBody3">
+    <style name="TextAppearance.Car.Body3">
         <item name="android:textStyle">normal</item>
         <item name="android:textSize">@dimen/car_body3_size</item>
         <item name="android:textColor">@color/car_body3</item>
@@ -105,14 +136,24 @@
 
     <!-- The smallest styling for body text. The color of this text changes based on the day/night
          mode. -->
-    <style name="CarBody4">
+    <style name="TextAppearance.Car.Body4">
         <item name="android:textStyle">normal</item>
         <item name="android:textSize">@dimen/car_body4_size</item>
         <item name="android:textColor">@color/car_body4</item>
     </style>
 
+    <!-- Styles for TextInputLayout hints. -->
+    <style name="TextAppearance.Car.Hint" parent="TextAppearance.Car.Body2" />
+
+    <!-- The styling for the action bar. -->
+    <style name="Widget.Car.Toolbar" parent="Widget.AppCompat.Toolbar">
+        <item name="titleTextAppearance">@style/TextAppearance.Car.Title.Light</item>
+        <item name="contentInsetStart">@dimen/car_keyline_1</item>
+        <item name="contentInsetEnd">@dimen/car_keyline_1</item>
+    </style>
+
     <!-- The style for the menu bar (i.e. hamburger) and back arrow in the navigation drawer. -->
-    <style name="DrawerArrowStyle" parent="Widget.AppCompat.DrawerArrowToggle">
+    <style name="Widget.Car.DrawerArrowToggle" parent="Widget.AppCompat.DrawerArrowToggle">
         <item name="color">@color/car_title_light</item>
         <item name="spinBars">true</item>
         <item name="barLength">@dimen/car_menu_bar_length</item>
@@ -125,6 +166,7 @@
 
     <!-- The styles for the regular and borderless buttons. -->
     <style name="Widget.Car.Button" parent="Widget.AppCompat.Button">
+        <item name="android:fontFamily">sans-serif-medium</item>
         <item name="android:layout_height">@dimen/car_button_height</item>
         <item name="android:minWidth">@dimen/car_button_min_width</item>
         <item name="android:paddingStart">@dimen/car_button_horizontal_padding</item>
@@ -134,8 +176,8 @@
         <item name="android:textColor">@drawable/car_button_text_color</item>
     </style>
 
-    <style name="Widget.Car.Button.Borderless.Colored"
-           parent="Widget.AppCompat.Button.Borderless.Colored">
+    <style name="Widget.Car.Button.Borderless.Colored" parent="Widget.AppCompat.Button.Borderless.Colored">
+        <item name="android:fontFamily">sans-serif-medium</item>
         <item name="android:layout_height">@dimen/car_button_height</item>
         <item name="android:minWidth">@dimen/car_button_min_width</item>
         <item name="android:paddingStart">@dimen/car_borderless_button_horizontal_padding</item>
@@ -145,15 +187,14 @@
     </style>
 
     <!-- Style for the progress bars. -->
-    <style name="Widget.Car.ProgressBar.Horizontal"
-           parent="Widget.AppCompat.ProgressBar.Horizontal">
+    <style name="Widget.Car.ProgressBar.Horizontal" parent="Widget.AppCompat.ProgressBar.Horizontal">
         <item name="android:minHeight">@dimen/car_progress_bar_height</item>
         <item name="android:maxHeight">@dimen/car_progress_bar_height</item>
     </style>
 
     <style name="Widget.Car.EditText" parent="Widget.AppCompat.EditText">
         <item name="android:textColor">?attr/editTextColor</item>
-        <item name="android:textAppearance">@style/CarBody1</item>
+        <item name="android:textAppearance">@style/TextAppearance.Car.Body1</item>
     </style>
 
     <!-- Style for the seek bars. -->
@@ -162,10 +203,6 @@
         <item name="android:thumb">@drawable/car_seekbar_thumb</item>
     </style>
 
-    <!-- Styles for TextInputLayout hints. -->
-    <style name="CarHintTextAppearance" parent="CarBody2">
-    </style>
-
     <style name="CarListVerticalDivider">
         <item name="android:layout_width">@dimen/car_vertical_line_divider_width</item>
         <item name="android:layout_height">@dimen/car_vertical_line_divider_height</item>
diff --git a/car/res/values/themes.xml b/car/res/values/themes.xml
index ebb57d8..2782536 100644
--- a/car/res/values/themes.xml
+++ b/car/res/values/themes.xml
@@ -14,18 +14,6 @@
 limitations under the License.
 -->
 <resources>
-    <!-- A Theme that activities should use to have correct arrow styling. -->
-    <style name="CarDrawerActivityTheme" parent="Theme.AppCompat.Light.NoActionBar">
-        <item name="drawerArrowStyle">@style/DrawerArrowStyle</item>
-    </style>
-
-    <!-- The styling for the action bar. -->
-    <style name="CarToolbarTheme">
-        <item name="titleTextAppearance">@style/CarTitle.Light</item>
-        <item name="contentInsetStart">@dimen/car_keyline_1</item>
-        <item name="contentInsetEnd">@dimen/car_keyline_1</item>
-    </style>
-
     <!-- Styles for Car Dialogs -->
     <style name="Theme.Car.Light.Dialog.Alert" parent="Theme.AppCompat.Light.Dialog.Alert">
         <item name="android:background">@color/car_card</item>
@@ -33,20 +21,21 @@
     </style>
 
     <!-- Base style for the Car -->
-    <style name="Theme.Car.NoActionBar" parent="Theme.AppCompat.NoActionBar">
+    <style name="Theme.Car.Light.NoActionBar" parent="Theme.AppCompat.Light.NoActionBar">
         <item name="android:colorAccent">@color/car_accent</item>
         <item name="android:colorButtonNormal">@color/car_accent</item>
         <item name="android:buttonStyle">@style/Widget.Car.Button</item>
-        <item name="android:borderlessButtonStyle">@style/Widget.Car.Button.Borderless.Colored
-        </item>
+        <item name="android:borderlessButtonStyle">@style/Widget.Car.Button.Borderless.Colored</item>
         <item name="android:alertDialogTheme">@style/Theme.Car.Light.Dialog.Alert</item>
-        <item name="android:progressBarStyleHorizontal">
-            @style/Widget.Car.ProgressBar.Horizontal
-        </item>
+        <item name="android:progressBarStyleHorizontal">@style/Widget.Car.ProgressBar.Horizontal</item>
         <item name="android:textColorHint">@color/car_body2</item>
         <item name="android:editTextStyle">@style/Widget.Car.EditText</item>
         <item name="android:editTextColor">@color/car_body1</item>
         <item name="android:colorControlNormal">@color/car_body2</item>
-        <item name="android:colorControlHighlight">?android:attr/colorAccent</item>
+    </style>
+
+    <!-- A Theme for activities that have a drawer affordance. -->
+    <style name="Theme.Car.Light.NoActionBar.Drawer">
+        <item name="drawerArrowStyle">@style/Widget.Car.DrawerArrowToggle</item>
     </style>
 </resources>
diff --git a/car/src/androidTest/AndroidManifest.xml b/car/src/androidTest/AndroidManifest.xml
index f50977a..79ac201 100644
--- a/car/src/androidTest/AndroidManifest.xml
+++ b/car/src/androidTest/AndroidManifest.xml
@@ -19,6 +19,8 @@
     <uses-sdk android:targetSdkVersion="${target-sdk-version}"/>
 
     <application android:supportsRtl="true">
+        <activity android:name="androidx.car.drawer.CarDrawerTestActivity"
+                  android:theme="@style/Theme.Car.Light.NoActionBar.Drawer" />
         <activity android:name="androidx.car.widget.ColumnCardViewTestActivity"/>
         <activity android:name="androidx.car.widget.PagedListViewSavedStateActivity"/>
         <activity android:name="androidx.car.widget.PagedListViewTestActivity"/>
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/androidTest/java/androidx/car/drawer/CarDrawerTest.java b/car/src/androidTest/java/androidx/car/drawer/CarDrawerTest.java
new file mode 100644
index 0000000..81ef980
--- /dev/null
+++ b/car/src/androidTest/java/androidx/car/drawer/CarDrawerTest.java
@@ -0,0 +1,154 @@
+/*
+ * 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.car.drawer;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.contrib.RecyclerViewActions.scrollToPosition;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.Matchers.lessThan;
+import static org.junit.Assume.assumeThat;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.espresso.contrib.DrawerActions;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import androidx.car.test.R;
+import androidx.car.utils.CarUxRestrictionsTestUtils;
+import androidx.car.widget.PagedListView;
+
+/**
+ * Unit tests for classes under {@link androidx.car.drawer}.
+ *
+ * <p>{@code mActivity} is a subclass of {@link CarDrawerActivity}. To set content of drawer, use
+ * {@link CarDrawerController#setRootAdapter(CarDrawerAdapter)}.
+ */
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public final class CarDrawerTest {
+    @Rule
+    public ActivityTestRule<CarDrawerTestActivity> mActivityRule;
+
+    private CarDrawerTestActivity mActivity;
+    private PagedListView mDrawerList;
+
+    /** Returns {@code true} if the testing device has the automotive feature flag. */
+    private boolean isAutoDevice() {
+        PackageManager packageManager = InstrumentationRegistry.getContext().getPackageManager();
+        return packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
+    }
+
+    @Before
+    public void setUp() {
+        Assume.assumeTrue(isAutoDevice());
+
+        // Inflate the activity here rather than initialization because it needs to happen after
+        // the isAutoDevice() check. Otherwise, errors will be thrown about "android.car.Car"
+        // classes not being found.
+        mActivityRule = new ActivityTestRule<>(CarDrawerTestActivity.class);
+
+        mActivity = mActivityRule.getActivity();
+        try {
+            mActivityRule.runOnUiThread(() -> {
+                mDrawerList = mActivity.findViewById(R.id.drawer_list);
+            });
+        } catch (Throwable throwable) {
+            throwable.printStackTrace();
+            throw new RuntimeException(throwable);
+        }
+    }
+
+    private DrawerItemViewHolder getViewHolderAtPositionInDrawer(int position) {
+        onView(withId(R.id.drawer_layout)).perform(DrawerActions.open());
+        return (DrawerItemViewHolder) mDrawerList.getRecyclerView()
+                .findViewHolderForAdapterPosition(position);
+    }
+
+    private void refreshUi() {
+        try {
+            mActivityRule.runOnUiThread(() -> mDrawerList.getAdapter().notifyDataSetChanged());
+        } catch (Throwable throwable) {
+            throwable.printStackTrace();
+            throw new RuntimeException(throwable);
+        }
+        // Wait for PagedListView to layout by using espresso to scroll to a position.
+        onView(withId(R.id.recycler_view)).perform(scrollToPosition(0));
+    }
+
+    @Test
+    public void testUxRestrictionsChange() throws Throwable {
+        String longText = mActivity.getResources().getString(R.string.over_uxr_text_length_limit);
+        CarDrawerAdapter adapter = new TextDrawerAdapter(mActivity, 5, longText);
+        mActivityRule.runOnUiThread(() -> mActivity.getDrawerController().setRootAdapter(adapter));
+
+        DrawerItemViewHolder vh = getViewHolderAtPositionInDrawer(0);
+        final String originalText = (String) vh.getText().getText();
+
+        vh.complyWithUxRestrictions(CarUxRestrictionsTestUtils.getFullyRestricted());
+        refreshUi();
+
+        assumeThat(vh.getText().getText().length(), is(lessThan(originalText.length())));
+    }
+
+    /**
+     * Drawer adapter that populates {@itemCount} items, each with text set to {@cod text}.
+     */
+    private static class TextDrawerAdapter extends CarDrawerAdapter {
+        private int mItemCount;
+        private String mText;
+
+        TextDrawerAdapter(Context context, int itemCount, String text) {
+            super(context, true);
+            mItemCount = itemCount;
+            mText = text;
+
+            setTitle("title");
+        }
+
+        @Override
+        protected int getActualItemCount() {
+            return mItemCount;
+        }
+
+        @Override
+        protected void populateViewHolder(DrawerItemViewHolder holder, int position) {
+            holder.getText().setText(mText);
+        }
+
+        @Override
+        public void onItemClick(int position) {
+            // Do nothing.
+        }
+
+        @Override
+        protected boolean usesSmallLayout(int position) {
+            return false;
+        }
+    }
+
+}
diff --git a/car/src/androidTest/java/androidx/car/drawer/CarDrawerTestActivity.java b/car/src/androidTest/java/androidx/car/drawer/CarDrawerTestActivity.java
new file mode 100644
index 0000000..c32574b
--- /dev/null
+++ b/car/src/androidTest/java/androidx/car/drawer/CarDrawerTestActivity.java
@@ -0,0 +1,35 @@
+/*
+ * 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.car.drawer;
+
+import android.os.Bundle;
+import android.widget.FrameLayout;
+
+/**
+ * Test activity for {@link CarDrawerActivity}.
+ *
+ * <p>This class sets MainContent as an empty {@link FrameLayout}, and does not provide drawer
+ * content. To populate drawer, use {@link CarDrawerController#setRootAdapter(CarDrawerAdapter)}
+ * to set implementation of {@link CarDrawerAdapter}.
+ */
+public final class CarDrawerTestActivity extends CarDrawerActivity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setMainContent(new FrameLayout(this));
+    }
+}
diff --git a/car/src/androidTest/java/androidx/car/utils/CarUxRestrictionsTestUtils.java b/car/src/androidTest/java/androidx/car/utils/CarUxRestrictionsTestUtils.java
new file mode 100644
index 0000000..15ff3f1
--- /dev/null
+++ b/car/src/androidTest/java/androidx/car/utils/CarUxRestrictionsTestUtils.java
@@ -0,0 +1,36 @@
+/*
+ * 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.car.utils;
+
+import android.car.drivingstate.CarUxRestrictions;
+
+/**
+ * Utility handy for testing functionality regarding
+ * {@link android.car.drivingstate.CarUxRestrictions}.
+ */
+public class CarUxRestrictionsTestUtils {
+
+    private CarUxRestrictionsTestUtils() {};
+
+    public static CarUxRestrictions getFullyRestricted() {
+        return new CarUxRestrictions(true, CarUxRestrictions.UX_RESTRICTIONS_FULLY_RESTRICTED, 0);
+    }
+
+    public static CarUxRestrictions getUnrestricted() {
+        return new CarUxRestrictions(false, CarUxRestrictions.UX_RESTRICTIONS_UNRESTRICTED, 0);
+    }
+}
diff --git a/car/src/androidTest/java/androidx/car/widget/DividerVisibilityManagerTest.java b/car/src/androidTest/java/androidx/car/widget/DividerVisibilityManagerTest.java
index fde098b..99747a3 100644
--- a/car/src/androidTest/java/androidx/car/widget/DividerVisibilityManagerTest.java
+++ b/car/src/androidTest/java/androidx/car/widget/DividerVisibilityManagerTest.java
@@ -16,7 +16,7 @@
 
 package androidx.car.widget;
 
-import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.closeTo;
 import static org.hamcrest.Matchers.greaterThan;
 import static org.hamcrest.Matchers.is;
 import static org.hamcrest.core.IsNull.notNullValue;
@@ -36,6 +36,7 @@
 import android.view.ViewGroup;
 import android.widget.TextView;
 
+import org.junit.Assume;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -67,18 +68,20 @@
     private DividerVisibilityManagerTestActivity mActivity;
     private PagedListView mPagedListView;
 
-    @Before
-    public void setUp() {
-        mActivity = mActivityRule.getActivity();
-        mPagedListView = mActivity.findViewById(R.id.paged_list_view_with_dividers);
-    }
-
     /** Returns {@code true} if the testing device has the automotive feature flag. */
     private boolean isAutoDevice() {
         PackageManager packageManager = mActivityRule.getActivity().getPackageManager();
         return packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
     }
 
+    @Before
+    public void setUp() {
+        Assume.assumeTrue(isAutoDevice());
+
+        mActivity = mActivityRule.getActivity();
+        mPagedListView = mActivity.findViewById(R.id.paged_list_view_with_dividers);
+    }
+
     /** Sets up {@link #mPagedListView} with the given number of items. */
     private void setUpPagedListView(int itemCount) {
         try {
@@ -95,10 +98,6 @@
 
     @Test
     public void setCustomDividerVisibilityManager() throws Throwable {
-        if (!isAutoDevice()) {
-            return;
-        }
-
         final int itemCount = 8;
         setUpPagedListView(itemCount /* itemCount */);
         RecyclerView.LayoutManager layoutManager =
@@ -117,8 +116,8 @@
             }
         });
         for (int i = 0; i < itemCount - 1; i++) {
-            assertThat(views[i + 1].getTop() - views[i].getBottom(),
-                    is(equalTo(2 * (dividerHeight / 2))));
+            assertThat((double) views[i + 1].getTop() - views[i].getBottom(),
+                    is(closeTo(2 * (dividerHeight / 2), 1.0f)));
         }
 
 
@@ -139,7 +138,7 @@
             if (dvm.shouldHideDivider(i)) {
                 assertEquals(distance, 0);
             } else {
-                assertEquals(distance, 2 * (dividerHeight / 2));
+                assertThat((double) distance, is(closeTo(2 * (dividerHeight / 2), 1.0f)));
             }
         }
     }
@@ -171,10 +170,6 @@
 
     @Test
     public void testSettingItemDividersHidden() throws Throwable {
-        if (!isAutoDevice()) {
-            return;
-        }
-
         TextListItem item0 = new TextListItem(mActivity);
         item0.setHideDivider(true);
 
diff --git a/car/src/androidTest/java/androidx/car/widget/PagedListViewSavedStateTest.java b/car/src/androidTest/java/androidx/car/widget/PagedListViewSavedStateTest.java
index a5405ac..19ffede 100644
--- a/car/src/androidTest/java/androidx/car/widget/PagedListViewSavedStateTest.java
+++ b/car/src/androidTest/java/androidx/car/widget/PagedListViewSavedStateTest.java
@@ -41,6 +41,7 @@
 
 import org.hamcrest.Matcher;
 import org.junit.After;
+import org.junit.Assume;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -83,6 +84,8 @@
 
     @Before
     public void setUp() {
+        Assume.assumeTrue(isAutoDevice());
+
         mActivity = mActivityRule.getActivity();
         mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
 
@@ -121,10 +124,6 @@
     @Suppress
     @Test
     public void testPagePositionRememberedOnRotation() {
-        if (!isAutoDevice()) {
-            return;
-        }
-
         LinearLayoutManager layoutManager1 =
                 (LinearLayoutManager) mPagedListView1.getRecyclerView().getLayoutManager();
         LinearLayoutManager layoutManager2 =
diff --git a/car/src/androidTest/java/androidx/car/widget/PagedListViewTest.java b/car/src/androidTest/java/androidx/car/widget/PagedListViewTest.java
index 995f200..1167a86 100644
--- a/car/src/androidTest/java/androidx/car/widget/PagedListViewTest.java
+++ b/car/src/androidTest/java/androidx/car/widget/PagedListViewTest.java
@@ -47,6 +47,7 @@
 import android.support.test.filters.MediumTest;
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
+import android.support.v7.widget.GridLayoutManager;
 import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
 import android.view.LayoutInflater;
@@ -59,6 +60,7 @@
 import org.hamcrest.Matcher;
 import org.hamcrest.TypeSafeMatcher;
 import org.junit.After;
+import org.junit.Assume;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -82,6 +84,10 @@
      */
     private static final int ITEMS_PER_PAGE = 5;
 
+    // For tests using GridLayoutManager - assuming each item takes one span, this is essentially
+    // number of items per row.
+    private static final int SPAN_COUNT = 5;
+
     @Rule
     public ActivityTestRule<PagedListViewTestActivity> mActivityRule =
             new ActivityTestRule<>(PagedListViewTestActivity.class);
@@ -89,13 +95,24 @@
     private PagedListViewTestActivity mActivity;
     private PagedListView mPagedListView;
     private ViewGroup.MarginLayoutParams mRecyclerViewLayoutParams;
+    private LinearLayoutManager mRecyclerViewLayoutManager;
+
+    /** Returns {@code true} if the testing device has the automotive feature flag. */
+    private boolean isAutoDevice() {
+        PackageManager packageManager = mActivityRule.getActivity().getPackageManager();
+        return packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
+    }
 
     @Before
     public void setUp() {
+        Assume.assumeTrue(isAutoDevice());
+
         mActivity = mActivityRule.getActivity();
         mPagedListView = mActivity.findViewById(R.id.paged_list_view);
         mRecyclerViewLayoutParams =
                 (ViewGroup.MarginLayoutParams) mPagedListView.getRecyclerView().getLayoutParams();
+        mRecyclerViewLayoutManager =
+                (LinearLayoutManager) mPagedListView.getRecyclerView().getLayoutManager();
 
         // Using deprecated Espresso methods instead of calling it on the IdlingRegistry because
         // the latter does not seem to work as reliably. Specifically, on the latter, it does
@@ -110,12 +127,6 @@
         }
     }
 
-    /** Returns {@code true} if the testing device has the automotive feature flag. */
-    private boolean isAutoDevice() {
-        PackageManager packageManager = mActivityRule.getActivity().getPackageManager();
-        return packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
-    }
-
     /** Sets up {@link #mPagedListView} with the given number of items. */
     private void setUpPagedListView(int itemCount) {
         try {
@@ -132,20 +143,12 @@
 
     @Test
     public void testScrollBarIsInvisibleIfItemsDoNotFillOnePage() {
-        if (!isAutoDevice()) {
-            return;
-        }
-
         setUpPagedListView(1 /* itemCount */);
         onView(withId(R.id.paged_scroll_view)).check(matches(not(isDisplayed())));
     }
 
     @Test
     public void testPageUpButtonDisabledAtTop() {
-        if (!isAutoDevice()) {
-            return;
-        }
-
         int itemCount = ITEMS_PER_PAGE * 3;
         setUpPagedListView(itemCount);
 
@@ -163,10 +166,6 @@
 
     @Test
     public void testItemSnappedToTopOfListOnScroll() throws InterruptedException {
-        if (!isAutoDevice()) {
-            return;
-        }
-
         // 2.5 so last page is not full
         setUpPagedListView((int) (ITEMS_PER_PAGE * 2.5 /* itemCount */));
 
@@ -177,10 +176,6 @@
 
     @Test
     public void testLastItemSnappedWhenBottomReached() {
-        if (!isAutoDevice()) {
-            return;
-        }
-
         // 2.5 so last page is not full
         setUpPagedListView((int) (ITEMS_PER_PAGE * 2.5 /* itemCount */));
 
@@ -188,12 +183,9 @@
         onView(withId(R.id.page_down)).perform(click());
         onView(withId(R.id.page_down)).perform(click()).check(matches(not(isEnabled())));
 
-        LinearLayoutManager layoutManager =
-                (LinearLayoutManager) mPagedListView.getRecyclerView().getLayoutManager();
-
         // Check that the last item is completely visible.
-        assertEquals(layoutManager.findLastCompletelyVisibleItemPosition(),
-                layoutManager.getItemCount() - 1);
+        assertEquals(mRecyclerViewLayoutManager.findLastCompletelyVisibleItemPosition(),
+                mRecyclerViewLayoutManager.getItemCount() - 1);
     }
 
     @Test
@@ -221,44 +213,32 @@
 
     @Test
     public void testPageUpAndDownMoveSameDistance() {
-        if (!isAutoDevice()) {
-            return;
-        }
-
         setUpPagedListView(ITEMS_PER_PAGE * 10);
 
         // Move down one page so there will be sufficient pages for up and downs.
         onView(withId(R.id.page_down)).perform(click());
 
-        LinearLayoutManager layoutManager =
-                (LinearLayoutManager) mPagedListView.getRecyclerView().getLayoutManager();
-
-        int topPosition = layoutManager.findFirstVisibleItemPosition();
+        int topPosition = mRecyclerViewLayoutManager.findFirstVisibleItemPosition();
 
         for (int i = 0; i < 3; i++) {
             onView(withId(R.id.page_down)).perform(click());
             onView(withId(R.id.page_up)).perform(click());
         }
 
-        assertThat(layoutManager.findFirstVisibleItemPosition(), is(equalTo(topPosition)));
+        assertThat(mRecyclerViewLayoutManager.findFirstVisibleItemPosition(),
+                is(equalTo(topPosition)));
     }
 
     @Test
     public void setItemSpacing() throws Throwable {
-        if (!isAutoDevice()) {
-            return;
-        }
-
         final int itemCount = 3;
         setUpPagedListView(itemCount /* itemCount */);
-        RecyclerView.LayoutManager layoutManager =
-                mPagedListView.getRecyclerView().getLayoutManager();
 
         // Initial spacing is 0.
         final View[] views = new View[itemCount];
         mActivityRule.runOnUiThread(() -> {
-            for (int i = 0; i < layoutManager.getChildCount(); i++) {
-                views[i] = layoutManager.getChildAt(i);
+            for (int i = 0; i < mRecyclerViewLayoutManager.getChildCount(); i++) {
+                views[i] = mRecyclerViewLayoutManager.getChildAt(i);
             }
         });
         for (int i = 0; i < itemCount - 1; i++) {
@@ -272,8 +252,8 @@
             mPagedListView.setItemSpacing(itemSpacing);
         });
         mActivityRule.runOnUiThread(() -> {
-            for (int i = 0; i < layoutManager.getChildCount(); i++) {
-                views[i] = layoutManager.getChildAt(i);
+            for (int i = 0; i < mRecyclerViewLayoutManager.getChildCount(); i++) {
+                views[i] = mRecyclerViewLayoutManager.getChildAt(i);
             }
         });
         for (int i = 0; i < itemCount - 1; i++) {
@@ -285,8 +265,8 @@
             mPagedListView.setItemSpacing(0);
         });
         mActivityRule.runOnUiThread(() -> {
-            for (int i = 0; i < layoutManager.getChildCount(); i++) {
-                views[i] = layoutManager.getChildAt(i);
+            for (int i = 0; i < mRecyclerViewLayoutManager.getChildCount(); i++) {
+                views[i] = mRecyclerViewLayoutManager.getChildAt(i);
             }
         });
         for (int i = 0; i < itemCount - 1; i++) {
@@ -297,10 +277,6 @@
     @Test
     @UiThreadTest
     public void testSetScrollBarButtonIcons() throws Throwable {
-        if (!isAutoDevice()) {
-            return;
-        }
-
         // Set up a pagedListView with a large item count to ensure the scroll bar buttons are
         // always showing.
         setUpPagedListView(100 /* itemCount */);
@@ -356,10 +332,6 @@
 
     @Test
     public void testDefaultScrollBarTopMargin() {
-        if (!isAutoDevice()) {
-            return;
-        }
-
         // Just need enough items to ensure the scroll bar is showing.
         setUpPagedListView(ITEMS_PER_PAGE * 10);
         onView(withId(R.id.paged_scroll_view)).check(matches(withTopMargin(0)));
@@ -367,10 +339,6 @@
 
     @Test
     public void testSetScrollbarTopMargin() {
-        if (!isAutoDevice()) {
-            return;
-        }
-
         // Just need enough items to ensure the scroll bar is showing.
         setUpPagedListView(ITEMS_PER_PAGE * 10);
 
@@ -382,27 +350,18 @@
 
     @Test
     public void testSwipingScrollbarDoesNotScrollList() {
-        if (!isAutoDevice()) {
-            return;
-        }
-
         // Just need enough items to ensure the scroll bar is showing.
         setUpPagedListView(ITEMS_PER_PAGE * 10);
 
         // Swipe on the filler instead of the whole scrollbar because buttons at top/bottom set
         // OnLongClickListener and thus eat the motion event.
         onView(withId(R.id.filler)).perform(swipeUp());
-        assertThat(((LinearLayoutManager) mPagedListView.getRecyclerView().getLayoutManager())
-                        .findFirstCompletelyVisibleItemPosition(),
+        assertThat(mRecyclerViewLayoutManager.findFirstCompletelyVisibleItemPosition(),
                 is(equalTo(0)));
     }
 
     @Test
     public void testSetGutterNone() {
-        if (!isAutoDevice()) {
-            return;
-        }
-
         // Just need enough items to ensure the scroll bar is showing.
         setUpPagedListView(ITEMS_PER_PAGE * 10);
 
@@ -414,10 +373,6 @@
 
     @Test
     public void testSetGutterStart() {
-        if (!isAutoDevice()) {
-            return;
-        }
-
         // Just need enough items to ensure the scroll bar is showing.
         setUpPagedListView(ITEMS_PER_PAGE * 10);
 
@@ -432,10 +387,6 @@
 
     @Test
     public void testSetGutterEnd() {
-        if (!isAutoDevice()) {
-            return;
-        }
-
         // Just need enough items to ensure the scroll bar is showing.
         setUpPagedListView(ITEMS_PER_PAGE * 10);
 
@@ -450,10 +401,6 @@
 
     @Test
     public void testSetGutterBoth() {
-        if (!isAutoDevice()) {
-            return;
-        }
-
         // Just need enough items to ensure the scroll bar is showing.
         setUpPagedListView(ITEMS_PER_PAGE * 10);
 
@@ -468,10 +415,6 @@
 
     @Test
     public void testSetGutterSizeNone() {
-        if (!isAutoDevice()) {
-            return;
-        }
-
         // Just need enough items to ensure the scroll bar is showing.
         setUpPagedListView(ITEMS_PER_PAGE * 10);
 
@@ -484,10 +427,6 @@
 
     @Test
     public void testSetGutterSizeStart() {
-        if (!isAutoDevice()) {
-            return;
-        }
-
         // Just need enough items to ensure the scroll bar is showing.
         setUpPagedListView(ITEMS_PER_PAGE * 10);
 
@@ -502,10 +441,6 @@
 
     @Test
     public void testSetGutterSizeEnd() {
-        if (!isAutoDevice()) {
-            return;
-        }
-
         // Just need enough items to ensure the scroll bar is showing.
         setUpPagedListView(ITEMS_PER_PAGE * 10);
 
@@ -520,10 +455,6 @@
 
     @Test
     public void testSetGutterSizeBoth() {
-        if (!isAutoDevice()) {
-            return;
-        }
-
         // Just need enough items to ensure the scroll bar is showing.
         setUpPagedListView(ITEMS_PER_PAGE * 10);
 
@@ -538,10 +469,6 @@
 
     @Test
     public void setDefaultScrollBarContainerWidth() {
-        if (!isAutoDevice()) {
-            return;
-        }
-
         // Just need enough items to ensure the scroll bar is showing.
         setUpPagedListView(ITEMS_PER_PAGE * 10);
 
@@ -553,10 +480,6 @@
 
     @Test
     public void testSetScrollBarContainerWidth() {
-        if (!isAutoDevice()) {
-            return;
-        }
-
         // Just need enough items to ensure the scroll bar is showing.
         setUpPagedListView(ITEMS_PER_PAGE * 10);
 
@@ -566,6 +489,33 @@
         onView(withId(R.id.paged_scroll_view)).check(matches(withWidth(scrollBarContainerWidth)));
     }
 
+    @Test
+    public void testTopOffsetInGridLayoutManager() throws Throwable {
+        int topOffset = mActivity.getResources().getDimensionPixelSize(R.dimen.car_padding_5);
+
+        // Need enough items to fill the first row.
+        setUpPagedListView(SPAN_COUNT * 3);
+        mActivityRule.runOnUiThread(() -> {
+            mPagedListView.setListContentTopOffset(topOffset);
+            mPagedListView.getRecyclerView().setLayoutManager(
+                    new GridLayoutManager(mActivity, SPAN_COUNT));
+            // Verify only items in first row have top offset. Setting no item spacing to avoid
+            // additional offset.
+            mPagedListView.setItemSpacing(0);
+        });
+        // Wait for paged list view to layout by using espresso to scroll to a position.
+        onView(withId(R.id.recycler_view)).perform(scrollToPosition(0));
+
+        for (int i = 0; i < SPAN_COUNT; i++) {
+            assertThat(mPagedListView.getRecyclerView().getChildAt(i).getTop(),
+                    is(equalTo(topOffset)));
+
+            // i + SPAN_COUNT uses items in second row.
+            assertThat(mPagedListView.getRecyclerView().getChildAt(i + SPAN_COUNT).getTop(),
+                    is(equalTo(mPagedListView.getRecyclerView().getChildAt(i).getBottom())));
+        }
+    }
+
     private static String itemText(int index) {
         return "Data " + index;
     }
@@ -575,9 +525,8 @@
      * is shown.
      */
     private void verifyItemSnappedToListTop() {
-        LinearLayoutManager layoutManager =
-                (LinearLayoutManager) mPagedListView.getRecyclerView().getLayoutManager();
-        int firstVisiblePosition = layoutManager.findFirstCompletelyVisibleItemPosition();
+        int firstVisiblePosition =
+                mRecyclerViewLayoutManager.findFirstCompletelyVisibleItemPosition();
         if (firstVisiblePosition > 1) {
             int lastInPreviousPagePosition = firstVisiblePosition - 1;
             onView(withText(itemText(lastInPreviousPagePosition)))
diff --git a/car/src/androidTest/java/androidx/car/widget/SeekbarListItemTest.java b/car/src/androidTest/java/androidx/car/widget/SeekbarListItemTest.java
index 7645c6d..207a51e 100644
--- a/car/src/androidTest/java/androidx/car/widget/SeekbarListItemTest.java
+++ b/car/src/androidTest/java/androidx/car/widget/SeekbarListItemTest.java
@@ -27,6 +27,7 @@
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 
+import android.content.pm.PackageManager;
 import android.graphics.Color;
 import android.graphics.drawable.ColorDrawable;
 import android.support.test.espresso.UiController;
@@ -39,6 +40,7 @@
 import android.widget.SeekBar;
 
 import org.hamcrest.Matcher;
+import org.junit.Assume;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -64,8 +66,14 @@
     private PagedListViewTestActivity mActivity;
     private PagedListView mPagedListView;
 
+    private boolean isAutoDevice() {
+        PackageManager packageManager = mActivityRule.getActivity().getPackageManager();
+        return packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
+    }
+
     @Before
     public void setUp() {
+        Assume.assumeTrue(isAutoDevice());
         mActivity = mActivityRule.getActivity();
         mPagedListView = mActivity.findViewById(R.id.paged_list_view);
     }
@@ -270,21 +278,6 @@
         }
     }
 
-    @Test
-    public void testTextLengthLimit() {
-        String longText = mActivity.getString(R.string.over_120_chars);
-        int lengthLimit = mActivity.getResources().getInteger(
-                R.integer.car_list_item_text_length_limit);
-        SeekbarListItem item0 = new SeekbarListItem(mActivity, 0, 0, null, longText);
-
-        List<ListItem> items = Arrays.asList(item0);
-        setupPagedListView(items);
-
-        assertThat(getViewHolderAtPosition(0).getText().getText().length(),
-                // add 1 for ellipsis character.
-                is(equalTo(lengthLimit + 1)));
-    }
-
     private static ViewAction clickChildViewWithId(final int id) {
         return new ViewAction() {
             @Override
diff --git a/car/src/androidTest/java/androidx/car/widget/TextListItemTest.java b/car/src/androidTest/java/androidx/car/widget/TextListItemTest.java
index 8371485..e7e8ec6 100644
--- a/car/src/androidTest/java/androidx/car/widget/TextListItemTest.java
+++ b/car/src/androidTest/java/androidx/car/widget/TextListItemTest.java
@@ -24,6 +24,7 @@
 
 import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.Matchers.greaterThanOrEqualTo;
+import static org.hamcrest.Matchers.lessThan;
 import static org.hamcrest.core.Is.is;
 import static org.hamcrest.core.IsEqual.equalTo;
 import static org.hamcrest.number.IsCloseTo.closeTo;
@@ -31,6 +32,7 @@
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 
+import android.content.pm.PackageManager;
 import android.graphics.drawable.Drawable;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.espresso.UiController;
@@ -39,12 +41,14 @@
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
 import android.support.v7.widget.LinearLayoutManager;
+import android.text.InputFilter;
 import android.text.TextUtils;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.RelativeLayout;
 
 import org.hamcrest.Matcher;
+import org.junit.Assume;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -53,8 +57,10 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Locale;
 
 import androidx.car.test.R;
+import androidx.car.utils.CarUxRestrictionsTestUtils;
 
 /**
 * Tests the layout configuration in {@link TextListItem}.
@@ -71,12 +77,32 @@
     private PagedListView mPagedListView;
     private ListItemAdapter mAdapter;
 
+    private boolean isAutoDevice() {
+        PackageManager packageManager = mActivityRule.getActivity().getPackageManager();
+        return packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
+    }
+
     @Before
     public void setUp() {
+        Assume.assumeTrue(isAutoDevice());
+
         mActivity = mActivityRule.getActivity();
         mPagedListView = mActivity.findViewById(R.id.paged_list_view);
     }
 
+    private void refreshUi() {
+        try {
+            mActivityRule.runOnUiThread(() -> {
+                mAdapter.notifyDataSetChanged();
+            });
+        } catch (Throwable throwable) {
+            throwable.printStackTrace();
+            throw new RuntimeException(throwable);
+        }
+        // Wait for paged list view to layout by using espresso to scroll to a position.
+        onView(withId(R.id.recycler_view)).perform(scrollToPosition(0));
+    }
+
     private void setupPagedListView(List<TextListItem> items) {
         ListItemProvider provider = new ListItemProvider.ListProvider(
                 new ArrayList<>(items));
@@ -89,8 +115,8 @@
             throwable.printStackTrace();
             throw new RuntimeException(throwable);
         }
-        // Wait for paged list view to layout by using espresso to scroll to a position.
-        onView(withId(R.id.recycler_view)).perform(scrollToPosition(0));
+
+        refreshUi();
     }
 
     private static void verifyViewIsHidden(View view) {
@@ -214,13 +240,8 @@
         setupPagedListView(Arrays.asList(item0));
 
         item0.setSwitchState(false);
-        try {
-            mActivityRule.runOnUiThread(() -> mAdapter.notifyItemChanged(0));
-        } catch (Throwable throwable) {
-            throwable.printStackTrace();
-        }
-        // Wait for paged list view to layout by using espresso to scroll to a position.
-        onView(withId(R.id.recycler_view)).perform(scrollToPosition(0));
+
+        refreshUi();
 
         TextListItem.ViewHolder viewHolder = getViewHolderAtPosition(0);
         assertThat(viewHolder.getSwitch().getVisibility(), is(equalTo(View.VISIBLE)));
@@ -233,13 +254,8 @@
         setupPagedListView(Arrays.asList(item0));
 
         item0.setSwitchState(false);
-        try {
-            mActivityRule.runOnUiThread(() -> mAdapter.notifyItemChanged(0));
-        } catch (Throwable throwable) {
-            throwable.printStackTrace();
-        }
-        // Wait for paged list view to layout by using espresso to scroll to a position.
-        onView(withId(R.id.recycler_view)).perform(scrollToPosition(0));
+
+        refreshUi();
 
         TextListItem.ViewHolder viewHolder = getViewHolderAtPosition(0);
         assertThat(viewHolder.getSwitch().getVisibility(), is(not(equalTo(View.VISIBLE))));
@@ -330,7 +346,7 @@
         // String wouldn't fit in one line.
         TextListItem item3 = new TextListItem(mActivity);
         item3.setTitle(InstrumentationRegistry.getContext().getResources().getString(
-                R.string.over_120_chars));
+                R.string.over_uxr_text_length_limit));
 
         List<TextListItem> items = Arrays.asList(item0, item1, item2, item3);
         setupPagedListView(items);
@@ -359,7 +375,7 @@
         // String wouldn't fit in one line.
         TextListItem item2 = new TextListItem(mActivity);
         item2.setBody(InstrumentationRegistry.getContext().getResources().getString(
-                R.string.over_120_chars));
+                R.string.over_uxr_text_length_limit));
 
         List<TextListItem> items = Arrays.asList(item0, item1, item2);
         setupPagedListView(items);
@@ -377,24 +393,6 @@
     }
 
     @Test
-    public void testBodyTextLengthLimit() {
-        final String longText = InstrumentationRegistry.getContext().getResources().getString(
-                R.string.over_120_chars);
-        final int limit = InstrumentationRegistry.getContext().getResources().getInteger(
-                R.integer.car_list_item_text_length_limit);
-
-        TextListItem item0 = new TextListItem(mActivity);
-        item0.setBody(longText);
-
-        List<TextListItem> items = Arrays.asList(item0);
-        setupPagedListView(items);
-
-        // + 1 for appended ellipsis.
-        assertThat(getViewHolderAtPosition(0).getBody().getText().length(),
-                is(equalTo(limit + 1)));
-    }
-
-    @Test
     public void testPrimaryIconDrawable() {
         Drawable drawable = InstrumentationRegistry.getContext().getResources().getDrawable(
                 android.R.drawable.sym_def_app_icon, null);
@@ -441,7 +439,7 @@
     @Test
     public void testSmallPrimaryIconTopMarginRemainsTheSameRegardlessOfTextLength() {
         final String longText = InstrumentationRegistry.getContext().getResources().getString(
-                R.string.over_120_chars);
+                R.string.over_uxr_text_length_limit);
 
         // Single line item.
         TextListItem item0 = new TextListItem(mActivity);
@@ -738,15 +736,56 @@
 
         String title = "updated title";
         item.setTitle(title);
-        mActivityRule.runOnUiThread(() -> mPagedListView.getAdapter().notifyItemChanged(0));
 
-        // Wait for paged list view to layout by using espresso to scroll to a position.
-        onView(withId(R.id.recycler_view)).perform(scrollToPosition(0));
+        refreshUi();
 
         TextListItem.ViewHolder viewHolder = getViewHolderAtPosition(0);
         assertThat(viewHolder.getTitle().getText(), is(equalTo(title)));
     }
 
+    @Test
+    public void testUxRestrictionsChange() throws Throwable {
+        String longText = mActivity.getString(R.string.over_uxr_text_length_limit);
+        TextListItem item = new TextListItem(mActivity);
+        item.setBody(longText);
+
+        setupPagedListView(Arrays.asList(item));
+
+        TextListItem.ViewHolder viewHolder = getViewHolderAtPosition(0);
+        // Default behavior without UXR is unrestricted.
+        assertThat(viewHolder.getBody().getText(), is(equalTo(longText)));
+
+        viewHolder.complyWithUxRestrictions(CarUxRestrictionsTestUtils.getFullyRestricted());
+
+        refreshUi();
+
+        // Verify that the body text length is limited.
+        assertThat(viewHolder.getBody().getText().length(), is(lessThan(longText.length())));
+    }
+
+    @Test
+    public void testUxRestrictionsChangesDoNotAlterExistingInputFilters() {
+        InputFilter filter = new InputFilter.AllCaps(Locale.US);
+        String bodyText = "bodytext";
+        TextListItem item = new TextListItem(mActivity);
+        item.setBody(bodyText);
+        item.addViewBinder(vh -> vh.getBody().setFilters(new InputFilter[] {filter}));
+
+        setupPagedListView(Arrays.asList(item));
+
+        TextListItem.ViewHolder viewHolder = getViewHolderAtPosition(0);
+
+        // Toggle UX restrictions between fully restricted and unrestricted should not affect
+        // existing filters.
+        viewHolder.complyWithUxRestrictions(CarUxRestrictionsTestUtils.getFullyRestricted());
+        refreshUi();
+        assertTrue(Arrays.asList(viewHolder.getBody().getFilters()).contains(filter));
+
+        viewHolder.complyWithUxRestrictions(CarUxRestrictionsTestUtils.getUnrestricted());
+        refreshUi();
+        assertTrue(Arrays.asList(viewHolder.getBody().getFilters()).contains(filter));
+    }
+
     private static ViewAction clickChildViewWithId(final int id) {
         return new ViewAction() {
             @Override
diff --git a/car/src/androidTest/res/layout/activity_paged_list_view.xml b/car/src/androidTest/res/layout/activity_paged_list_view.xml
index d7c8946..eab4dfa 100644
--- a/car/src/androidTest/res/layout/activity_paged_list_view.xml
+++ b/car/src/androidTest/res/layout/activity_paged_list_view.xml
@@ -25,6 +25,5 @@
         android:id="@+id/paged_list_view"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        app:showPagedListViewDivider="false"
-        app:offsetScrollBar="true"/>
+        app:showPagedListViewDivider="false"/>
 </FrameLayout>
diff --git a/car/src/androidTest/res/layout/paged_list_item_column_card.xml b/car/src/androidTest/res/layout/paged_list_item_column_card.xml
index 5028abf..245aad1 100644
--- a/car/src/androidTest/res/layout/paged_list_item_column_card.xml
+++ b/car/src/androidTest/res/layout/paged_list_item_column_card.xml
@@ -17,19 +17,14 @@
 <FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:orientation="vertical">
-
+    android:layout_height="wrap_content">
     <androidx.car.widget.ColumnCardView
         android:id="@+id/column_card"
         android:layout_width="match_parent"
         android:layout_height="wrap_content">
-
         <TextView
             android:id="@+id/text_view"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"/>
-
     </androidx.car.widget.ColumnCardView>
-
 </FrameLayout>
diff --git a/car/src/androidTest/res/values/strings.xml b/car/src/androidTest/res/values/strings.xml
index 478abc4..5051442 100644
--- a/car/src/androidTest/res/values/strings.xml
+++ b/car/src/androidTest/res/values/strings.xml
@@ -14,5 +14,5 @@
 limitations under the License.
 -->
 <resources>
-    <string name="over_120_chars">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</string>
+    <string name="over_uxr_text_length_limit">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</string>
 </resources>
diff --git a/car/src/main/java/androidx/car/app/CarListDialog.java b/car/src/main/java/androidx/car/app/CarListDialog.java
new file mode 100644
index 0000000..4a7becf
--- /dev/null
+++ b/car/src/main/java/androidx/car/app/CarListDialog.java
@@ -0,0 +1,390 @@
+/*
+ * 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.car.app;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v7.widget.RecyclerView;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.view.Window;
+import android.view.WindowManager;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import androidx.car.R;
+import androidx.car.widget.DayNightStyle;
+import androidx.car.widget.ListItem;
+import androidx.car.widget.ListItemAdapter;
+import androidx.car.widget.ListItemProvider;
+import androidx.car.widget.PagedListView;
+import androidx.car.widget.PagedScrollBarView;
+import androidx.car.widget.TextListItem;
+
+/**
+ * A subclass of {@link Dialog} that is tailored for the car environment. This dialog can display a
+ * fixed list of items. There is no affordance for setting titles or any other text.
+ *
+ * <p>Its functionality is similar to if a list has been set on
+ * {@link android.support.v7.app.AlertDialog}, but is styled so that it is more appropriate for
+ * displaying in vehicles.
+ *
+ * <p>Note that this dialog cannot be created with an empty list.
+ */
+public class CarListDialog extends Dialog {
+    private static final String TAG = "CarListDialog";
+
+    private ListItemAdapter mAdapter;
+    private PagedListView mList;
+    private PagedScrollBarView mScrollBarView;
+    private final DialogInterface.OnClickListener mOnClickListener;
+
+    /** Flag for if a touch on the scrim of the dialog will dismiss it. */
+    private boolean mDismissOnTouchOutside;
+
+    private final ViewTreeObserver.OnGlobalLayoutListener mLayoutListener =
+            new ViewTreeObserver.OnGlobalLayoutListener() {
+                @Override
+                public void onGlobalLayout() {
+                    updateScrollbar();
+                    // Remove this listener because the listener for the scroll state will be
+                    // enough to keep the scrollbar in sync.
+                    mList.getViewTreeObserver().removeOnGlobalLayoutListener(this);
+                }
+            };
+
+    private CarListDialog(Context context, String[] items, OnClickListener listener) {
+        super(context);
+        mOnClickListener = listener;
+        initializeAdapter(items);
+    }
+
+    @Override
+    public void setTitle(CharSequence title) {
+        // Ideally this method should not exist; the list dialog does not support a title.
+        // Unfortunately, this method is defined with the Dialog itself and is public. So, throw
+        // an error if this method is ever called.
+        throw new UnsupportedOperationException("Title is not supported in the CarListDialog");
+    }
+
+    /**
+     * @see super#setCanceledOnTouchOutside(boolean)
+     */
+    @Override
+    public void setCanceledOnTouchOutside(boolean cancel) {
+        super.setCanceledOnTouchOutside(cancel);
+        // Need to override this method to save the value of cancel.
+        mDismissOnTouchOutside = cancel;
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        Window window = getWindow();
+        window.setContentView(R.layout.car_list_dialog);
+
+        // By default, the decor background is white. Set this to be transparent so that
+        // the dialog can have rounded corners and will show the background.
+        window.getDecorView().setBackgroundColor(Color.TRANSPARENT);
+
+        // Ensure that the dialog takes up the entire window. This is needed because the scrollbar
+        // needs to be drawn off the dialog.
+        WindowManager.LayoutParams layoutParams = window.getAttributes();
+        layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
+        layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
+        window.setAttributes(layoutParams);
+
+        // The container for this dialog takes up the entire screen. As a result, need to manually
+        // listen for clicks and dismiss the dialog when necessary.
+        window.findViewById(R.id.container).setOnClickListener(v -> handleTouchOutside());
+
+        initializeList();
+        initializeScrollbar();
+    }
+
+    @Override
+    protected void onStop() {
+        // Cleanup to ensure that no stray view observers are still attached.
+        if (mList != null) {
+            mList.getViewTreeObserver().removeOnGlobalLayoutListener(mLayoutListener);
+        }
+
+        super.onStop();
+    }
+
+    private void initializeList() {
+        mList = getWindow().findViewById(R.id.list);
+        mList.setAdapter(mAdapter);
+
+        // Ensure that when the list is scrolled, the scrollbar updates to reflect the new position.
+        mList.getRecyclerView().addOnScrollListener(new RecyclerView.OnScrollListener() {
+            @Override
+            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
+                super.onScrolled(recyclerView, dx, dy);
+                updateScrollbar();
+            }
+        });
+
+        // Update if the scrollbar should be visible after the PagedListView has finished
+        // laying itself out. This is needed because the only way to the state of scrollbar is to
+        // see the items after they have been laid out.
+        mList.getViewTreeObserver().addOnGlobalLayoutListener(mLayoutListener);
+    }
+
+    /**
+     * Initializes the scrollbar that appears off the dialog. This scrollbar is not the one that
+     * usually appears with the PagedListView, but mimics it in functionality.
+     */
+    private void initializeScrollbar() {
+        mScrollBarView = getWindow().findViewById(R.id.scrollbar);
+        mScrollBarView.setDayNightStyle(DayNightStyle.FORCE_NIGHT);
+
+        mScrollBarView.setPaginationListener(direction -> {
+            switch (direction) {
+                case PagedScrollBarView.PaginationListener.PAGE_UP:
+                    mList.pageUp();
+                    break;
+                case PagedScrollBarView.PaginationListener.PAGE_DOWN:
+                    mList.pageDown();
+                    break;
+                default:
+                    Log.e(TAG, "Unknown pagination direction (" + direction + ")");
+            }
+        });
+    }
+
+    /**
+     * Handles if a touch has been detected outside of the dialog. If
+     * {@link #mDismissOnTouchOutside} has been set, then the dialog will be dismissed.
+     */
+    private void handleTouchOutside() {
+        if (mDismissOnTouchOutside) {
+            dismiss();
+        }
+    }
+
+    /**
+     * Initializes {@link #mAdapter} to display the items in the given array. It utilizes the
+     * {@link TextListItem} but only populates the title field with the the values in the array.
+     */
+    private void initializeAdapter(String[] items) {
+        Context context = getContext();
+        List<ListItem> listItems = new ArrayList<>();
+
+        for (int i = 0; i < items.length; i++) {
+            TextListItem item = new TextListItem(getContext());
+            item.setTitle(items[i]);
+
+            // Save the position to pass to onItemClick().
+            final int position = i;
+            item.setOnClickListener(v -> onItemClick(position));
+
+            listItems.add(item);
+        }
+
+        mAdapter = new ListItemAdapter(context, new ListItemProvider.ListProvider(listItems));
+    }
+
+    /**
+     * Check if a click listener has been set on this dialog and notify that a click has happened
+     * at the given item position, then dismisses this dialog. If no listener has been set, the
+     * dialog just dismisses.
+     */
+    private void onItemClick(int position) {
+        if (mOnClickListener != null) {
+            mOnClickListener.onClick(this /* dialog */, position);
+        }
+        dismiss();
+    }
+
+    /**
+     * Determines if scrollbar should be visible or not and shows/hides it accordingly.
+     *
+     * <p>If this is being called as a result of adapter changes, it should be called after the new
+     * layout has been calculated because the method of determining scrollbar visibility uses the
+     * current layout.
+     *
+     * <p>If this is called after an adapter change but before the new layout, the visibility
+     * determination may not be correct.
+     */
+    private void updateScrollbar() {
+        RecyclerView recyclerView = mList.getRecyclerView();
+        RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
+
+        boolean isAtStart = mList.isAtStart();
+        boolean isAtEnd = mList.isAtEnd();
+
+        if ((isAtStart && isAtEnd)) {
+            mScrollBarView.setVisibility(View.INVISIBLE);
+            return;
+        }
+
+        mScrollBarView.setVisibility(View.VISIBLE);
+        mScrollBarView.setUpEnabled(!isAtStart);
+        mScrollBarView.setDownEnabled(!isAtEnd);
+
+        // Assume the list scrolls vertically because we control the list and know the
+        // LayoutManager cannot change.
+        mScrollBarView.setParameters(
+                recyclerView.computeVerticalScrollRange(),
+                recyclerView.computeVerticalScrollOffset(),
+                recyclerView.computeVerticalScrollExtent(),
+                false /* animate */);
+
+        getWindow().getDecorView().invalidate();
+    }
+
+    /**
+     * Builder class that can be used to create a {@link CarListDialog} by configuring the
+     * options for the list and behavior of the dialog.
+     */
+    public static class Builder {
+        private final Context mContext;
+        private String[] mItems;
+        private DialogInterface.OnClickListener mOnClickListener;
+
+        private boolean mCancelable = true;
+        private OnCancelListener mOnCancelListener;
+        private OnDismissListener mOnDismissListener;
+
+        /**
+         * Creates a new instance of the {@code Builder}.
+         *
+         * @param context The {@code Context} that the dialog is to be created in.
+         */
+        public Builder(Context context) {
+            mContext = context;
+        }
+
+        /**
+         * Sets the items that should appear in the list. The dialog will automatically dismiss
+         * itself when an item in the list is clicked on.
+         *
+         * <p>If a {@link DialogInterface.OnClickListener} is given, then it will be notified
+         * of the click. The dialog will still be dismissed afterwards. The {@code which}
+         * parameter of the {@link DialogInterface.OnClickListener#onClick(DialogInterface, int)}
+         * method will be the position of the item. This position maps to the index of the item in
+         * the given list.
+         *
+         * <p>The provided list of items cannot be {@code null} or empty. Passing an empty list
+         * to this method will throw can exception.
+         *
+         * @param items The items that will appear in the list.
+         * @param onClickListener The listener that will be notified of a click.
+         * @return This {@code Builder} object to allow for chaining of calls.
+         */
+        public Builder setItems(@NonNull String[] items,
+                @Nullable OnClickListener onClickListener) {
+            if (items == null || items.length == 0) {
+                throw new IllegalArgumentException("Provided list of items cannot be empty.");
+            }
+
+            mItems = items;
+            mOnClickListener = onClickListener;
+            return this;
+        }
+
+        /**
+         * Sets whether the dialog is cancelable or not. Default is {@code true}.
+         *
+         * @return This {@code Builder} object to allow for chaining of calls.
+         */
+        public Builder setCancelable(boolean cancelable) {
+            mCancelable = cancelable;
+            return this;
+        }
+
+        /**
+         * Sets the callback that will be called if the dialog is canceled.
+         *
+         * <p>Even in a cancelable dialog, the dialog may be dismissed for reasons other than
+         * being canceled or one of the supplied choices being selected.
+         * If you are interested in listening for all cases where the dialog is dismissed
+         * and not just when it is canceled, see {@link #setOnDismissListener(OnDismissListener)}.
+         *
+         * @param onCancelListener The listener to be invoked when this dialog is canceled.
+         * @return This {@code Builder} object to allow for chaining of calls.
+         *
+         * @see #setCancelable(boolean)
+         * @see #setOnDismissListener(OnDismissListener)
+         */
+        public Builder setOnCancelListener(OnCancelListener onCancelListener) {
+            mOnCancelListener = onCancelListener;
+            return this;
+        }
+
+        /**
+         * Sets the callback that will be called when the dialog is dismissed for any reason.
+         *
+         * @return This {@code Builder} object to allow for chaining of calls.
+         */
+        public Builder setOnDismissListener(OnDismissListener onDismissListener) {
+            mOnDismissListener = onDismissListener;
+            return this;
+        }
+
+        /**
+         * Creates an {@link CarListDialog} with the arguments supplied to this {@code Builder}.
+         *
+         * <p>If {@link #setItems(String[],DialogInterface.OnClickListener)} is never called, then
+         * calling this method will throw an exception.
+         *
+         * <p>Calling this method does not display the dialog. If no additional processing is
+         * needed, {@link #show()} may be called instead to both create and display the dialog.
+         */
+        public CarListDialog create() {
+            if (mItems == null || mItems.length == 0) {
+                throw new IllegalStateException(
+                        "CarListDialog must be created with a non-empty list.");
+            }
+
+            CarListDialog dialog = new CarListDialog(mContext, mItems, mOnClickListener);
+
+            dialog.setCancelable(mCancelable);
+            dialog.setCanceledOnTouchOutside(mCancelable);
+            dialog.setOnCancelListener(mOnCancelListener);
+            dialog.setOnDismissListener(mOnDismissListener);
+
+            return dialog;
+        }
+
+        /**
+         * Creates an {@link CarAlertDialog} with the arguments supplied to this {@code Builder}
+         * and immediately displays the dialog.
+         *
+         * <p>Calling this method is functionally identical to:
+         * <pre>
+         *     CarAlertDialog dialog = new CarAlertDialog.Builder().create();
+         *     dialog.show();
+         * </pre>
+         */
+        public CarListDialog show() {
+            CarListDialog dialog = create();
+            dialog.show();
+            return dialog;
+        }
+    }
+}
diff --git a/car/src/main/java/androidx/car/drawer/CarDrawerActivity.java b/car/src/main/java/androidx/car/drawer/CarDrawerActivity.java
index 3929cca..e768ea8 100644
--- a/car/src/main/java/androidx/car/drawer/CarDrawerActivity.java
+++ b/car/src/main/java/androidx/car/drawer/CarDrawerActivity.java
@@ -60,8 +60,8 @@
  * CarDrawerAdapter for the next level to
  * {@link CarDrawerController#pushAdapter(CarDrawerAdapter)}.
  *
- * <p>Any Activity's based on this class need to set their theme to CarDrawerActivityTheme or a
- * derivative.
+ * <p>Any Activity's based on this class need to set their theme to
+ * {@code Theme.Car.Light.NoActionBar.Drawer} or a derivative.
  */
 public class CarDrawerActivity extends AppCompatActivity {
     private static final int ANIMATION_DURATION_MS = 100;
diff --git a/car/src/main/java/androidx/car/drawer/CarDrawerAdapter.java b/car/src/main/java/androidx/car/drawer/CarDrawerAdapter.java
index ca16413..e6ea158 100644
--- a/car/src/main/java/androidx/car/drawer/CarDrawerAdapter.java
+++ b/car/src/main/java/androidx/car/drawer/CarDrawerAdapter.java
@@ -16,9 +16,18 @@
 
 package androidx.car.drawer;
 
+import android.app.Activity;
+import android.car.Car;
+import android.car.CarNotConnectedException;
+import android.car.drivingstate.CarUxRestrictions;
+import android.car.drivingstate.CarUxRestrictionsManager;
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.ServiceConnection;
 import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.os.IBinder;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.v7.widget.RecyclerView;
@@ -40,6 +49,10 @@
  *
  * <p>This class also takes care of implementing the PageListView.ItemCamp contract and subclasses
  * should implement {@link #getActualItemCount()}.
+ *
+ * <p>To enable support for {@link CarUxRestrictions}, call {@link #start()} in your
+ * {@code Activity}'s {@link android.app.Activity#onCreate(Bundle)}, and {@link #stop()} in
+ * {@link Activity#onStop()}.
  */
 public abstract class CarDrawerAdapter extends RecyclerView.Adapter<DrawerItemViewHolder>
         implements PagedListView.ItemCap, DrawerItemClickListener {
@@ -49,6 +62,69 @@
     private CharSequence mTitle;
     private TitleChangeListener mTitleChangeListener;
 
+    private final Car mCar;
+    @Nullable private CarUxRestrictionsManager mCarUxRestrictionsManager;
+    private CarUxRestrictions mCurrentUxRestrictions;
+    // Keep onUxRestrictionsChangedListener an internal var to avoid exposing APIs from android.car.
+    // Otherwise car sample apk will fail at compile time due to not having access to the stubs.
+    private CarUxRestrictionsManager.onUxRestrictionsChangedListener mUxrChangeListener =
+            new CarUxRestrictionsManager.onUxRestrictionsChangedListener() {
+        @Override
+        public void onUxRestrictionsChanged(CarUxRestrictions carUxRestrictions) {
+            mCurrentUxRestrictions = carUxRestrictions;
+            notifyDataSetChanged();
+        }
+    };
+
+    private final ServiceConnection mServiceConnection = new ServiceConnection() {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            try {
+                mCarUxRestrictionsManager = (CarUxRestrictionsManager)
+                        mCar.getCarManager(Car.CAR_UX_RESTRICTION_SERVICE);
+                mCarUxRestrictionsManager.registerListener(mUxrChangeListener);
+                mUxrChangeListener.onUxRestrictionsChanged(
+                        mCarUxRestrictionsManager.getCurrentCarUxRestrictions());
+            } catch (CarNotConnectedException e) {
+                e.printStackTrace();
+            }
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            try {
+                mCarUxRestrictionsManager.unregisterListener();
+                mCarUxRestrictionsManager = null;
+            } catch (CarNotConnectedException e) {
+                e.printStackTrace();
+            }
+        }
+    };
+
+    /**
+     * Enables support for {@link CarUxRestrictions}.
+     *
+     * <p>This method can be called from {@code Activity}'s {@link Activity#onStart()}, or at the
+     * time of construction.
+     *
+     * <p>This method must be accompanied with a matching {@link #stop()} to avoid leak.
+     */
+    public void start() {
+        if (!mCar.isConnected()) {
+            mCar.connect();
+        }
+    }
+
+    /**
+     * Disables support for {@link CarUxRestrictions}, and frees up resources.
+     *
+     * <p>This method should be called from {@code Activity}'s {@link Activity#onStop()}, or at the
+     * time of this adapter being discarded.
+     */
+    public void stop() {
+        mCar.disconnect();
+    }
+
     /**
      * Interface for a class that will be notified a new title has been set on this adapter.
      */
@@ -66,6 +142,8 @@
         mEmptyListDrawable = context.getDrawable(R.drawable.ic_list_view_disable);
         mEmptyListDrawable.setColorFilter(context.getColor(R.color.car_tint),
                 PorterDuff.Mode.SRC_IN);
+
+        mCar = Car.createCar(context, mServiceConnection);
     }
 
     /** Returns the title set via {@link #setTitle(CharSequence)}. */
@@ -159,6 +237,11 @@
             holder.setItemClickListener(this);
             populateViewHolder(holder, position);
         }
+
+        // Car may not be initialized thus current UXR will not be available.
+        if (mCurrentUxRestrictions != null) {
+            holder.complyWithUxRestrictions(mCurrentUxRestrictions);
+        }
     }
 
     /**
diff --git a/car/src/main/java/androidx/car/drawer/DrawerItemViewHolder.java b/car/src/main/java/androidx/car/drawer/DrawerItemViewHolder.java
index 8bbded9..8994444 100644
--- a/car/src/main/java/androidx/car/drawer/DrawerItemViewHolder.java
+++ b/car/src/main/java/androidx/car/drawer/DrawerItemViewHolder.java
@@ -16,6 +16,7 @@
 
 package androidx.car.drawer;
 
+import android.car.drivingstate.CarUxRestrictions;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.v7.widget.RecyclerView;
@@ -24,6 +25,7 @@
 import android.widget.TextView;
 
 import androidx.car.R;
+import androidx.car.utils.CarUxRestrictionsUtils;
 
 /**
  * Re-usable {@link RecyclerView.ViewHolder} for displaying items in the
@@ -85,4 +87,15 @@
                 ? v -> listener.onItemClick(getAdapterPosition())
                 : null);
     }
+
+    /**
+     * Update children views to comply with car UX restrictions.
+     *
+     * <p>{@code Text} might be truncated to meet length limit required by regulation.
+     *
+     * @param restrictions current car UX restrictions.
+     */
+    public void complyWithUxRestrictions(CarUxRestrictions restrictions) {
+        CarUxRestrictionsUtils.comply(itemView.getContext(), restrictions, getText());
+    }
 }
diff --git a/car/src/main/java/androidx/car/moderator/SpeedBumpController.java b/car/src/main/java/androidx/car/moderator/SpeedBumpController.java
index 750a967..21cf124 100644
--- a/car/src/main/java/androidx/car/moderator/SpeedBumpController.java
+++ b/car/src/main/java/androidx/car/moderator/SpeedBumpController.java
@@ -16,10 +16,18 @@
 
 package androidx.car.moderator;
 
+import android.car.Car;
+import android.car.CarNotConnectedException;
+import android.car.drivingstate.CarUxRestrictions;
+import android.car.drivingstate.CarUxRestrictionsManager;
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.ServiceConnection;
 import android.graphics.drawable.AnimatedVectorDrawable;
 import android.os.Handler;
-import android.support.annotation.VisibleForTesting;
+import android.os.IBinder;
+import android.support.annotation.Nullable;
+import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
@@ -34,6 +42,8 @@
  * {@link SpeedBumpView}.
  */
 class SpeedBumpController {
+    private static final String TAG = "SpeedBumpController";
+
     /**
      * The number of permitted actions that are acquired per second that the user has not
      * interacted with the {@code SpeedBumpView}.
@@ -41,8 +51,7 @@
     private static final float ACQUIRED_PERMITS_PER_SECOND = 0.5f;
 
     /** The maximum number of permits that can be acquired when the user is idling. */
-    @VisibleForTesting
-    static final float MAX_PERMIT_POOL = 5f;
+    private static final float MAX_PERMIT_POOL = 5f;
 
     /** The delay between when the permit pool has been depleted and when it begins to refill. */
     private static final long PERMIT_FILL_DELAY_MS = 600L;
@@ -52,6 +61,11 @@
             MAX_PERMIT_POOL,
             PERMIT_FILL_DELAY_MS);
 
+    // mCar is created in the constructor, but can be null if connection to the car is not
+    // successful.
+    @Nullable private final Car mCar;
+    @Nullable private CarUxRestrictionsManager mCarUxRestrictionsManager;
+
     /**
      * Whether or not the user is currently allowed to interact with any child views of
      * {@code SpeedBumpView}.
@@ -78,6 +92,39 @@
         mLockoutImageView = mLockoutMessageView.findViewById(R.id.lock_out_drawable);
         mLockOutMessageDurationMs =
                 mContext.getResources().getInteger(R.integer.speed_bump_lock_out_duration_ms);
+
+        mCar = Car.createCar(mContext, mServiceConnection);
+
+        // By default, no limiting until UXR restrictions kick in.
+        mContentRateLimiter.setUnlimitedMode(true);
+    }
+
+    /**
+     * Starts this {@code SpeedBumpController} for monitoring any changes in driving restrictions.
+     */
+    void start() {
+        try {
+            if (mCar != null && !mCar.isConnected()) {
+                mCar.connect();
+            }
+        } catch (IllegalStateException e) {
+            // Do nothing.
+            Log.w(TAG, "start(); cannot connect to Car");
+        }
+    }
+
+    /**
+     * Stops this {@code SpeedBumpController} from monitoring any changes in driving restrictions.
+     */
+    void stop() {
+        try {
+            if (mCar != null && mCar.isConnected()) {
+                mCar.disconnect();
+            }
+        } catch (IllegalStateException e) {
+            // Do nothing.
+            Log.w(TAG, "stop(); cannot disconnect from Car");
+        }
     }
 
     /**
@@ -180,4 +227,42 @@
         });
         mLockoutMessageView.startAnimation(lockOutMessageOut);
     }
+
+    /**
+     * Updates whether or not the {@link #mContentRateLimiter} is set in unlimited mode based on
+     * the given {@link CarUxRestrictions}.
+     *
+     * <p>If driver optimization is required, then unlimited mode is off.
+     */
+    private void updateUnlimitedModeEnabled(CarUxRestrictions restrictions) {
+        // If driver optimization is not required, then there is no need to limit anything.
+        mContentRateLimiter.setUnlimitedMode(!restrictions.isRequiresDistractionOptimization());
+    }
+
+    private final ServiceConnection mServiceConnection = new ServiceConnection() {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            try {
+                mCarUxRestrictionsManager = (CarUxRestrictionsManager)
+                        mCar.getCarManager(Car.CAR_UX_RESTRICTION_SERVICE);
+                mCarUxRestrictionsManager.registerListener(
+                        SpeedBumpController.this::updateUnlimitedModeEnabled);
+
+                updateUnlimitedModeEnabled(
+                        mCarUxRestrictionsManager.getCurrentCarUxRestrictions());
+            } catch (CarNotConnectedException e) {
+                e.printStackTrace();
+            }
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            try {
+                mCarUxRestrictionsManager.unregisterListener();
+                mCarUxRestrictionsManager = null;
+            } catch (CarNotConnectedException e) {
+                e.printStackTrace();
+            }
+        }
+    };
 }
diff --git a/car/src/main/java/androidx/car/moderator/SpeedBumpView.java b/car/src/main/java/androidx/car/moderator/SpeedBumpView.java
index ad65c6a..b07eec6 100644
--- a/car/src/main/java/androidx/car/moderator/SpeedBumpView.java
+++ b/car/src/main/java/androidx/car/moderator/SpeedBumpView.java
@@ -17,7 +17,6 @@
 package androidx.car.moderator;
 
 import android.content.Context;
-import android.support.annotation.VisibleForTesting;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 import android.view.View;
@@ -56,13 +55,16 @@
         addView(mSpeedBumpController.getLockoutMessageView());
     }
 
-    /**
-     * Returns the view that is responsible for displaying a message telling the user that they
-     * have been locked out from further interaction.
-     */
-    @VisibleForTesting
-    View getLockOutMessageView() {
-        return mSpeedBumpController.getLockoutMessageView();
+    @Override
+    public void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        mSpeedBumpController.start();
+    }
+
+    @Override
+    public void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        mSpeedBumpController.stop();
     }
 
     @Override
diff --git a/car/src/main/java/androidx/car/utils/CarUxRestrictionsUtils.java b/car/src/main/java/androidx/car/utils/CarUxRestrictionsUtils.java
new file mode 100644
index 0000000..6b4019c
--- /dev/null
+++ b/car/src/main/java/androidx/car/utils/CarUxRestrictionsUtils.java
@@ -0,0 +1,73 @@
+/*
+ * 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.car.utils;
+
+import android.car.drivingstate.CarUxRestrictions;
+import android.content.Context;
+import android.text.InputFilter;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import androidx.car.R;
+
+/**
+ * Utility class that helps {@code View}s comply with {@link CarUxRestrictions}.
+ */
+public class CarUxRestrictionsUtils {
+
+    private CarUxRestrictionsUtils() {};
+
+    private static InputFilter sStringLengthFilter;
+
+    /**
+     * Updates a {@code TextView} to comply with active UX restrictions.
+     *
+     * <p>Adds/removes a {@link android.text.InputFilter.LengthFilter} that truncates the text
+     * in {@code TextView}.
+     *
+     * @param carUxRestrictions current Car UX restrictions.
+     * @param tv TextView to be updated to comply with UX restrictions.
+     */
+    public static void comply(Context context, CarUxRestrictions carUxRestrictions, TextView tv) {
+        if (sStringLengthFilter == null) {
+            int lengthLimit = context.getResources().getInteger(
+                    R.integer.car_list_item_text_length_limit);
+            sStringLengthFilter = new InputFilter.LengthFilter(lengthLimit);
+        }
+
+        int activeUxr = carUxRestrictions.getActiveRestrictions();
+
+        // Note the list returned by Arrays.asList does not support structural modification.
+        List<InputFilter> filters = Arrays.asList(tv.getFilters());
+        if ((activeUxr & CarUxRestrictions.UX_RESTRICTIONS_LIMIT_STRING_LENGTH) != 0) {
+            // Check whether length filter exists to avoid unnecessary array operations.
+            if (!filters.contains(sStringLengthFilter)) {
+                ArrayList<InputFilter> updatedFilters = new ArrayList<>(filters);
+                updatedFilters.add(sStringLengthFilter);
+                tv.setFilters(updatedFilters.toArray(new InputFilter[updatedFilters.size()]));
+            }
+        } else if (filters.contains(sStringLengthFilter)) {
+            ArrayList<InputFilter> updatedFilters = new ArrayList<>(filters);
+            updatedFilters.remove(sStringLengthFilter);
+            tv.setFilters(updatedFilters.toArray(new InputFilter[updatedFilters.size()]));
+        }
+    }
+}
+
diff --git a/car/src/main/java/androidx/car/utils/ColumnCalculator.java b/car/src/main/java/androidx/car/utils/ColumnCalculator.java
index 35b1a91..39f5b28 100644
--- a/car/src/main/java/androidx/car/utils/ColumnCalculator.java
+++ b/car/src/main/java/androidx/car/utils/ColumnCalculator.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.content.res.Resources;
+import android.support.annotation.Px;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.view.WindowManager;
@@ -105,6 +106,7 @@
      *
      * @return The width of a single column in pixels.
      */
+    @Px
     public int getColumnWidth() {
         return mColumnWidth;
     }
@@ -124,6 +126,7 @@
      *
      * @return The size of a single gutter in pixels.
      */
+    @Px
     public int getGutterSize() {
         return mGutterSize;
     }
@@ -135,6 +138,7 @@
      *
      * @return The size in pixels for a given column span.
      */
+    @Px
     public int getSizeForColumnSpan(int columnSpan) {
         int gutterSpan = columnSpan - 1;
         return columnSpan * mColumnWidth + gutterSpan * mGutterSize;
diff --git a/car/src/main/java/androidx/car/widget/GridLayoutManagerUtils.java b/car/src/main/java/androidx/car/widget/GridLayoutManagerUtils.java
new file mode 100644
index 0000000..27c1f17
--- /dev/null
+++ b/car/src/main/java/androidx/car/widget/GridLayoutManagerUtils.java
@@ -0,0 +1,95 @@
+/*
+ * 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.car.widget;
+
+import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.view.View;
+
+/**
+ * Utility class that helps navigating in GridLayoutManager.
+ *
+ * <p>Assumes parameter {@code RecyclerView} uses {@link GridLayoutManager}.
+ *
+ * <p>Assumes the orientation of {@code GridLayoutManager} is vertical.
+ */
+class GridLayoutManagerUtils {
+    private GridLayoutManagerUtils() {}
+
+    /**
+     * @param parent RecyclerView that uses GridLayoutManager as LayoutManager.
+     * @return number of items in the first row in {@code RecyclerView}.
+     */
+    public static int getFirstRowItemCount(RecyclerView parent) {
+        GridLayoutManager manager = (GridLayoutManager) parent.getLayoutManager();
+        int itemCount = parent.getAdapter().getItemCount();
+        int spanCount = manager.getSpanCount();
+
+        int spanSum = 0;
+        int pos = 0;
+        while (pos < itemCount && spanSum < spanCount) {
+            spanSum += manager.getSpanSizeLookup().getSpanSize(pos);
+            pos += 1;
+        }
+        // pos will be either the first item in second row, or item count when items not fill
+        // the first row.
+        return pos;
+    }
+
+    /**
+     * Returns the span index of an item.
+     */
+    public static int getSpanIndex(View item) {
+        GridLayoutManager.LayoutParams layoutParams =
+                ((GridLayoutManager.LayoutParams) item.getLayoutParams());
+        return layoutParams.getSpanIndex();
+    }
+
+    /**
+     * Returns the span size of an item. {@code item} must be already laid out.
+     */
+    public static int getSpanSize(View item) {
+        GridLayoutManager.LayoutParams layoutParams =
+                ((GridLayoutManager.LayoutParams) item.getLayoutParams());
+        return layoutParams.getSpanSize();
+    }
+
+    /**
+     * Returns the index of the last item that is on the same row as {@code index}.
+     *
+     * @param index index of child {@code View} in {@code parent}.
+     * @param parent {@link RecyclerView} that contains the View {@code index} points to.
+     */
+    public static int getLastIndexOnSameRow(int index, RecyclerView parent) {
+        int spanCount = ((GridLayoutManager) parent.getLayoutManager()).getSpanCount();
+        int spanSum = GridLayoutManagerUtils.getSpanIndex(parent.getChildAt(index));
+        for (int i = index; i < parent.getChildCount(); i++) {
+            spanSum += GridLayoutManagerUtils.getSpanSize(parent.getChildAt(i));
+            if (spanSum > spanCount) {
+                // We have reached next row.
+
+                // Implicit constraint by grid layout manager:
+                // Initial spanSum + spanSize would not exceed spanCount, so it's safe to
+                // subtract 1.
+                return i - 1;
+            }
+        }
+        // Still have not reached row end. Assuming the list only scrolls vertically, we are at
+        // the last row.
+        return parent.getChildCount() - 1;
+    }
+}
diff --git a/car/src/main/java/androidx/car/widget/ListItem.java b/car/src/main/java/androidx/car/widget/ListItem.java
index 97e8fca..014ffd7 100644
--- a/car/src/main/java/androidx/car/widget/ListItem.java
+++ b/car/src/main/java/androidx/car/widget/ListItem.java
@@ -1,5 +1,6 @@
 package androidx.car.widget;
 
+import android.car.drivingstate.CarUxRestrictions;
 import android.support.annotation.Nullable;
 import android.support.v7.widget.RecyclerView;
 import android.view.View;
@@ -214,5 +215,12 @@
                 mCleanUps.add(cleanUp);
             }
         }
+
+        /**
+         * Update children views to comply with UX restriction changes.
+         *
+         * @param restrictions current car UX restrictions.
+         */
+        public abstract void complyWithUxRestrictions(CarUxRestrictions restrictions);
     }
 }
diff --git a/car/src/main/java/androidx/car/widget/ListItemAdapter.java b/car/src/main/java/androidx/car/widget/ListItemAdapter.java
index 78b1d6e..43e924f 100644
--- a/car/src/main/java/androidx/car/widget/ListItemAdapter.java
+++ b/car/src/main/java/androidx/car/widget/ListItemAdapter.java
@@ -16,8 +16,18 @@
 
 package androidx.car.widget;
 
+import android.app.Activity;
+import android.car.Car;
+import android.car.CarNotConnectedException;
+import android.car.drivingstate.CarUxRestrictions;
+import android.car.drivingstate.CarUxRestrictionsManager;
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.IBinder;
 import android.support.annotation.LayoutRes;
+import android.support.annotation.Nullable;
 import android.support.v7.widget.CardView;
 import android.support.v7.widget.RecyclerView;
 import android.util.SparseArray;
@@ -41,6 +51,9 @@
  *     individual {@link ListItem}.
  * </ul>
  *
+ * <p>To enable support for {@link CarUxRestrictions}, call {@link #start()} in your
+ * {@code Activity}'s {@link android.app.Activity#onCreate(Bundle)}, and {@link #stop()} in
+ * {@link Activity#onStop()}.
  */
 public class ListItemAdapter extends
         RecyclerView.Adapter<ListItem.ViewHolder> implements PagedListView.ItemCap,
@@ -77,6 +90,68 @@
     private final SparseArray<Function<View, ListItem.ViewHolder>> mViewHolderCreator =
             new SparseArray<>();
 
+    private final Car mCar;
+    @Nullable private CarUxRestrictionsManager mCarUxRestrictionsManager;
+    private CarUxRestrictions mCurrentUxRestrictions;
+    // Keep onUxRestrictionsChangedListener an internal var to avoid exposing APIs from android.car.
+    // Otherwise car sample apk will fail at compile time due to not having access to the stubs.
+    private CarUxRestrictionsManager.onUxRestrictionsChangedListener mUxrChangeListener =
+            new CarUxRestrictionsManager.onUxRestrictionsChangedListener() {
+        @Override
+        public void onUxRestrictionsChanged(CarUxRestrictions carUxRestrictions) {
+            mCurrentUxRestrictions = carUxRestrictions;
+            notifyDataSetChanged();
+        }
+    };
+    private final ServiceConnection mServiceConnection = new ServiceConnection() {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            try {
+                mCarUxRestrictionsManager = (CarUxRestrictionsManager)
+                        mCar.getCarManager(Car.CAR_UX_RESTRICTION_SERVICE);
+                mCarUxRestrictionsManager.registerListener(mUxrChangeListener);
+                mUxrChangeListener.onUxRestrictionsChanged(
+                        mCarUxRestrictionsManager.getCurrentCarUxRestrictions());
+            } catch (CarNotConnectedException e) {
+                e.printStackTrace();
+            }
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            try {
+                mCarUxRestrictionsManager.unregisterListener();
+                mCarUxRestrictionsManager = null;
+            } catch (CarNotConnectedException e) {
+                e.printStackTrace();
+            }
+        }
+    };
+
+    /**
+     * Enables support for {@link CarUxRestrictions}.
+     *
+     * <p>This method can be called from {@code Activity}'s {@link Activity#onStart()}, or at the
+     * time of construction.
+     *
+     * <p>This method must be accompanied with a matching {@link #stop()} to avoid leak.
+     */
+    public void start() {
+        if (!mCar.isConnected()) {
+            mCar.connect();
+        }
+    }
+
+    /**
+     * Disables support for {@link CarUxRestrictions}, and frees up resources.
+     *
+     * <p>This method should be called from {@code Activity}'s {@link Activity#onStop()}, or at the
+     * time of this adapter being discarded.
+     */
+    public void stop() {
+        mCar.disconnect();
+    }
+
     /**
      * Registers a function that returns {@link android.support.v7.widget.RecyclerView.ViewHolder}
      * for its matching view type returned by {@link ListItem#getViewType()}.
@@ -118,6 +193,8 @@
                 R.layout.car_list_item_text_content, TextListItem::createViewHolder);
         registerListItemViewType(LIST_ITEM_TYPE_SEEKBAR,
                 R.layout.car_list_item_seekbar_content, SeekbarListItem::createViewHolder);
+
+        mCar = Car.createCar(context, mServiceConnection);
     }
 
     @Override
@@ -183,6 +260,11 @@
             ListItemBackgroundResolver.setBackground(
                     holder.itemView, position, mItemProvider.size());
         }
+
+        // Car may not be initialized thus current UXR will not be available.
+        if (mCurrentUxRestrictions != null) {
+            holder.complyWithUxRestrictions(mCurrentUxRestrictions);
+        }
     }
 
     @Override
diff --git a/car/src/main/java/androidx/car/widget/PagedListView.java b/car/src/main/java/androidx/car/widget/PagedListView.java
index 1f0f9df..c8cfd37 100644
--- a/car/src/main/java/androidx/car/widget/PagedListView.java
+++ b/car/src/main/java/androidx/car/widget/PagedListView.java
@@ -16,6 +16,8 @@
 
 package androidx.car.widget;
 
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
@@ -31,8 +33,10 @@
 import android.support.annotation.IntDef;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
 import android.support.annotation.UiThread;
 import android.support.annotation.VisibleForTesting;
+import android.support.v7.widget.GridLayoutManager;
 import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
 import android.util.AttributeSet;
@@ -165,8 +169,7 @@
      */
     public interface DividerVisibilityManager {
         /**
-         * Given an item position, returns whether the divider coming after that item should be
-         * hidden.
+         * Given an item position, returns whether the divider below that item should be hidden.
          *
          * @param position item position inside the adapter.
          * @return true if divider is to be hidden, false if divider should be shown.
@@ -718,13 +721,21 @@
         return position / mRowsPerPage;
     }
 
-    /** Scrolls the contents of the RecyclerView up a page. */
-    private void pageUp() {
+    /**
+     * Scrolls the contents of the RecyclerView up a page.
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    public void pageUp() {
         mRecyclerView.fling(0, FLING_UP_DISTANCE);
     }
 
-    /** Scrolls the contents of the RecyclerView down a page. */
-    private void pageDown() {
+    /**
+     * Scrolls the contents of the RecyclerView down a page.
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    public void pageDown() {
         mRecyclerView.fling(0, FLING_DOWN_DISTANCE);
     }
 
@@ -1056,8 +1067,9 @@
             super.getItemOffsets(outRect, view, parent, state);
             int position = parent.getChildAdapterPosition(view);
 
-            // Skip offset for last item.
-            if (position == state.getItemCount() - 1) {
+            // Skip offset for last item except for GridLayoutManager.
+            if (position == state.getItemCount() - 1
+                    && !(parent.getLayoutManager() instanceof GridLayoutManager)) {
                 return;
             }
 
@@ -1110,7 +1122,7 @@
 
         /** Updates the list divider color which may have changed due to a day night transition. */
         public void updateDividerColor() {
-            mPaint.setColor(mContext.getResources().getColor(R.color.car_list_divider));
+            mPaint.setColor(mContext.getResources().getColor(R.color.car_list_divider, null));
         }
 
         /** Sets {@link DividerVisibilityManager} on the DividerDecoration.*/
@@ -1120,67 +1132,84 @@
 
         @Override
         public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
-            // Draw a divider line between each item. No need to draw the line for the last item.
-            for (int i = 0, childCount = parent.getChildCount(); i < childCount - 1; i++) {
+            boolean usesGridLayoutManager = parent.getLayoutManager() instanceof GridLayoutManager;
+            for (int i = 0; i < parent.getChildCount(); i++) {
                 View container = parent.getChildAt(i);
-
-                // if divider should be hidden for this item, proceeds without drawing it
                 int itemPosition = parent.getChildAdapterPosition(container);
+
                 if (hideDividerForAdapterPosition(itemPosition)) {
                     continue;
                 }
 
-                View nextContainer = parent.getChildAt(i + 1);
-                int spacing = nextContainer.getTop() - container.getBottom();
-
-                View startChild =
-                        mDividerStartId != INVALID_RESOURCE_ID
-                                ? container.findViewById(mDividerStartId)
-                                : container;
-
-                View endChild =
-                        mDividerEndId != INVALID_RESOURCE_ID
-                                ? container.findViewById(mDividerEndId)
-                                : container;
-
-                if (startChild == null || endChild == null) {
+                View nextVerticalContainer;
+                if (usesGridLayoutManager) {
+                    // Find an item in next row to calculate vertical space.
+                    int lastItem = GridLayoutManagerUtils.getLastIndexOnSameRow(i, parent);
+                    nextVerticalContainer = parent.getChildAt(lastItem + 1);
+                } else {
+                    nextVerticalContainer = parent.getChildAt(i + 1);
+                }
+                if (nextVerticalContainer == null) {
+                    // Skip drawing divider for the last row in GridLayoutManager, or the last
+                    // item (presumably in LinearLayoutManager).
                     continue;
                 }
-
-                Rect containerRect = new Rect();
-                container.getGlobalVisibleRect(containerRect);
-
-                Rect startRect = new Rect();
-                startChild.getGlobalVisibleRect(startRect);
-
-                Rect endRect = new Rect();
-                endChild.getGlobalVisibleRect(endRect);
-
-                int left = container.getLeft() + mDividerStartMargin
-                        + (startRect.left - containerRect.left);
-                int right = container.getRight() - (endRect.right - containerRect.right);
-                int bottom = container.getBottom() + spacing / 2 + mDividerHeight / 2;
-                int top = bottom - mDividerHeight;
-
-                c.drawRect(left, top, right, bottom, mPaint);
+                int spacing = nextVerticalContainer.getTop() - container.getBottom();
+                drawDivider(c, container, spacing);
             }
         }
 
+        /**
+         * Draws a divider under {@code container}.
+         *
+         * @param spacing between {@code container} and next view.
+         */
+        private void drawDivider(Canvas c, View container, int spacing) {
+            View startChild =
+                    mDividerStartId != INVALID_RESOURCE_ID
+                            ? container.findViewById(mDividerStartId)
+                            : container;
+
+            View endChild =
+                    mDividerEndId != INVALID_RESOURCE_ID
+                            ? container.findViewById(mDividerEndId)
+                            : container;
+
+            if (startChild == null || endChild == null) {
+                return;
+            }
+
+            Rect containerRect = new Rect();
+            container.getGlobalVisibleRect(containerRect);
+
+            Rect startRect = new Rect();
+            startChild.getGlobalVisibleRect(startRect);
+
+            Rect endRect = new Rect();
+            endChild.getGlobalVisibleRect(endRect);
+
+            int left = container.getLeft() + mDividerStartMargin
+                    + (startRect.left - containerRect.left);
+            int right = container.getRight() - (endRect.right - containerRect.right);
+            int bottom = container.getBottom() + spacing / 2 + mDividerHeight / 2;
+            int top = bottom - mDividerHeight;
+
+            c.drawRect(left, top, right, bottom, mPaint);
+        }
+
         @Override
         public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
                 RecyclerView.State state) {
             super.getItemOffsets(outRect, view, parent, state);
             int pos = parent.getChildAdapterPosition(view);
-
-            // Skip top offset when there is no divider above.
-            if (pos > 0 && !hideDividerForAdapterPosition(pos - 1)) {
-                outRect.top = mDividerHeight / 2;
+            if (hideDividerForAdapterPosition(pos)) {
+                return;
             }
-
-            // Skip bottom offset when there is no divider below.
-            if (pos < state.getItemCount() - 1 && !hideDividerForAdapterPosition(pos)) {
-                outRect.bottom = mDividerHeight / 2;
-            }
+            // Add an bottom offset to all items that should have divider, even when divider is not
+            // drawn for the bottom item(s).
+            // With GridLayoutManager it's difficult to tell whether a view is in the last row.
+            // This is to keep expected behavior consistent.
+            outRect.bottom = mDividerHeight;
         }
 
         private boolean hideDividerForAdapterPosition(int position) {
@@ -1204,9 +1233,13 @@
                 RecyclerView.State state) {
             super.getItemOffsets(outRect, view, parent, state);
             int position = parent.getChildAdapterPosition(view);
-
-            // Only set the offset for the first item.
-            if (position == 0) {
+            if (parent.getLayoutManager() instanceof GridLayoutManager
+                    && position < GridLayoutManagerUtils.getFirstRowItemCount(parent)) {
+                // For GridLayoutManager, top offset should be set for all items in the first row.
+                // Otherwise the top items will be visually uneven.
+                outRect.top = mTopOffset;
+            } else if (position == 0) {
+                 // Only set the offset for the first item.
                 outRect.top = mTopOffset;
             }
         }
diff --git a/car/src/main/java/androidx/car/widget/SeekbarListItem.java b/car/src/main/java/androidx/car/widget/SeekbarListItem.java
index 2e98817..0136cd2 100644
--- a/car/src/main/java/androidx/car/widget/SeekbarListItem.java
+++ b/car/src/main/java/androidx/car/widget/SeekbarListItem.java
@@ -18,6 +18,7 @@
 
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
+import android.car.drivingstate.CarUxRestrictions;
 import android.content.Context;
 import android.graphics.drawable.Drawable;
 import android.support.annotation.DrawableRes;
@@ -38,6 +39,7 @@
 import java.util.List;
 
 import androidx.car.R;
+import androidx.car.utils.CarUxRestrictionsUtils;
 
 /**
  * Class to build a list item with {@link SeekBar}.
@@ -122,8 +124,7 @@
      * @param max the upper range of the SeekBar.
      * @param progress the current progress of the specified value.
      * @param listener listener to receive notification of changes to progress level.
-     * @param text displays a text on top of the SeekBar. Text beyond length required by
-     *             regulation will be truncated. null value hides the text field.
+     * @param text displays a text on top of the SeekBar.
      */
     public SeekbarListItem(Context context, int max, int progress,
             SeekBar.OnSeekBarChangeListener listener, String text) {
@@ -132,14 +133,7 @@
         mMax = max;
         mProgress = progress;
         mOnSeekBarChangeListener = listener;
-
-        int limit = mContext.getResources().getInteger(
-                R.integer.car_list_item_text_length_limit);
-        if (TextUtils.isEmpty(text) || text.length() < limit) {
-            mText = text;
-        } else {
-            mText = text.substring(0, limit) + mContext.getString(R.string.ellipsis);
-        }
+        mText = text;
 
         markDirty();
     }
@@ -278,7 +272,7 @@
             if (!TextUtils.isEmpty(mText)) {
                 vh.getText().setVisibility(View.VISIBLE);
                 vh.getText().setText(mText);
-                vh.getText().setTextAppearance(R.style.CarBody1);
+                vh.getText().setTextAppearance(R.style.TextAppearance_Car_Body1);
             }
         });
     }
@@ -525,6 +519,11 @@
             mSupplementalIconDivider = itemView.findViewById(R.id.supplemental_icon_divider);
         }
 
+        @Override
+        public void complyWithUxRestrictions(CarUxRestrictions restrictions) {
+            CarUxRestrictionsUtils.comply(itemView.getContext(), restrictions, getText());
+        }
+
         public RelativeLayout getContainerLayout() {
             return mContainerLayout;
         }
diff --git a/car/src/main/java/androidx/car/widget/TextListItem.java b/car/src/main/java/androidx/car/widget/TextListItem.java
index c87321c..df8d5fa 100644
--- a/car/src/main/java/androidx/car/widget/TextListItem.java
+++ b/car/src/main/java/androidx/car/widget/TextListItem.java
@@ -18,6 +18,7 @@
 
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
+import android.car.drivingstate.CarUxRestrictions;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
@@ -39,6 +40,7 @@
 import java.util.List;
 
 import androidx.car.R;
+import androidx.car.utils.CarUxRestrictionsUtils;
 
 /**
  * Class to build a list item of text.
@@ -341,13 +343,13 @@
 
         if (mIsBodyPrimary) {
             mBinders.add(vh -> {
-                vh.getTitle().setTextAppearance(R.style.CarBody2);
-                vh.getBody().setTextAppearance(R.style.CarBody1);
+                vh.getTitle().setTextAppearance(R.style.TextAppearance_Car_Body2);
+                vh.getBody().setTextAppearance(R.style.TextAppearance_Car_Body1);
             });
         } else {
             mBinders.add(vh -> {
-                vh.getTitle().setTextAppearance(R.style.CarBody1);
-                vh.getBody().setTextAppearance(R.style.CarBody2);
+                vh.getTitle().setTextAppearance(R.style.TextAppearance_Car_Body1);
+                vh.getBody().setTextAppearance(R.style.TextAppearance_Car_Body2);
             });
         }
     }
@@ -585,19 +587,11 @@
     /**
      * Sets the body text of item.
      *
-     * <p>Text beyond length required by regulation will be truncated.
-     *
      * @param body text to be displayed.
      * @param asPrimary sets {@code Body Text} as primary text of item.
      */
     public void setBody(String body, boolean asPrimary) {
-        int limit = mContext.getResources().getInteger(
-                R.integer.car_list_item_text_length_limit);
-        if (body.length() < limit) {
-            mBody = body;
-        } else {
-            mBody = body.substring(0, limit) + mContext.getString(R.string.ellipsis);
-        }
+        mBody = body;
         mIsBodyPrimary = asPrimary;
 
         markDirty();
@@ -762,6 +756,18 @@
             mAction2Divider = itemView.findViewById(R.id.action2_divider);
         }
 
+        /**
+         * Update children views to comply with car UX restrictions.
+         *
+         * <p>{@code Body} text might be truncated to meet length limit required by regulation.
+         *
+         * @param restrictions current car UX restrictions.
+         */
+        @Override
+        public void complyWithUxRestrictions(CarUxRestrictions restrictions) {
+            CarUxRestrictionsUtils.comply(itemView.getContext(), restrictions, getBody());
+        }
+
         public RelativeLayout getContainerLayout() {
             return mContainerLayout;
         }
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/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 e1b5a11..35bcb40 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);
@@ -267,6 +314,7 @@
     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
@@ -306,18 +354,18 @@
     ctor public NotificationCompat.Action.WearableExtender(android.support.v4.app.NotificationCompat.Action);
     method public android.support.v4.app.NotificationCompat.Action.WearableExtender clone();
     method public android.support.v4.app.NotificationCompat.Action.Builder extend(android.support.v4.app.NotificationCompat.Action.Builder);
-    method public java.lang.CharSequence getCancelLabel();
-    method public java.lang.CharSequence getConfirmLabel();
+    method public deprecated java.lang.CharSequence getCancelLabel();
+    method public deprecated java.lang.CharSequence getConfirmLabel();
     method public boolean getHintDisplayActionInline();
     method public boolean getHintLaunchesActivity();
-    method public java.lang.CharSequence getInProgressLabel();
+    method public deprecated java.lang.CharSequence getInProgressLabel();
     method public boolean isAvailableOffline();
     method public android.support.v4.app.NotificationCompat.Action.WearableExtender setAvailableOffline(boolean);
-    method public android.support.v4.app.NotificationCompat.Action.WearableExtender setCancelLabel(java.lang.CharSequence);
-    method public android.support.v4.app.NotificationCompat.Action.WearableExtender setConfirmLabel(java.lang.CharSequence);
+    method public deprecated android.support.v4.app.NotificationCompat.Action.WearableExtender setCancelLabel(java.lang.CharSequence);
+    method public deprecated android.support.v4.app.NotificationCompat.Action.WearableExtender setConfirmLabel(java.lang.CharSequence);
     method public android.support.v4.app.NotificationCompat.Action.WearableExtender setHintDisplayActionInline(boolean);
     method public android.support.v4.app.NotificationCompat.Action.WearableExtender setHintLaunchesActivity(boolean);
-    method public android.support.v4.app.NotificationCompat.Action.WearableExtender setInProgressLabel(java.lang.CharSequence);
+    method public deprecated android.support.v4.app.NotificationCompat.Action.WearableExtender setInProgressLabel(java.lang.CharSequence);
   }
 
   public static class NotificationCompat.BigPictureStyle extends android.support.v4.app.NotificationCompat.Style {
@@ -495,39 +543,39 @@
     method public android.graphics.Bitmap getBackground();
     method public java.lang.String getBridgeTag();
     method public int getContentAction();
-    method public int getContentIcon();
-    method public int getContentIconGravity();
+    method public deprecated int getContentIcon();
+    method public deprecated int getContentIconGravity();
     method public boolean getContentIntentAvailableOffline();
-    method public int getCustomContentHeight();
-    method public int getCustomSizePreset();
+    method public deprecated int getCustomContentHeight();
+    method public deprecated int getCustomSizePreset();
     method public java.lang.String getDismissalId();
     method public android.app.PendingIntent getDisplayIntent();
-    method public int getGravity();
+    method public deprecated int getGravity();
     method public boolean getHintAmbientBigPicture();
-    method public boolean getHintAvoidBackgroundClipping();
+    method public deprecated boolean getHintAvoidBackgroundClipping();
     method public boolean getHintContentIntentLaunchesActivity();
-    method public boolean getHintHideIcon();
-    method public int getHintScreenTimeout();
-    method public boolean getHintShowBackgroundOnly();
+    method public deprecated boolean getHintHideIcon();
+    method public deprecated int getHintScreenTimeout();
+    method public deprecated boolean getHintShowBackgroundOnly();
     method public java.util.List<android.app.Notification> getPages();
     method public boolean getStartScrollBottom();
     method public android.support.v4.app.NotificationCompat.WearableExtender setBackground(android.graphics.Bitmap);
     method public android.support.v4.app.NotificationCompat.WearableExtender setBridgeTag(java.lang.String);
     method public android.support.v4.app.NotificationCompat.WearableExtender setContentAction(int);
-    method public android.support.v4.app.NotificationCompat.WearableExtender setContentIcon(int);
-    method public android.support.v4.app.NotificationCompat.WearableExtender setContentIconGravity(int);
+    method public deprecated android.support.v4.app.NotificationCompat.WearableExtender setContentIcon(int);
+    method public deprecated android.support.v4.app.NotificationCompat.WearableExtender setContentIconGravity(int);
     method public android.support.v4.app.NotificationCompat.WearableExtender setContentIntentAvailableOffline(boolean);
-    method public android.support.v4.app.NotificationCompat.WearableExtender setCustomContentHeight(int);
-    method public android.support.v4.app.NotificationCompat.WearableExtender setCustomSizePreset(int);
+    method public deprecated android.support.v4.app.NotificationCompat.WearableExtender setCustomContentHeight(int);
+    method public deprecated android.support.v4.app.NotificationCompat.WearableExtender setCustomSizePreset(int);
     method public android.support.v4.app.NotificationCompat.WearableExtender setDismissalId(java.lang.String);
     method public android.support.v4.app.NotificationCompat.WearableExtender setDisplayIntent(android.app.PendingIntent);
-    method public android.support.v4.app.NotificationCompat.WearableExtender setGravity(int);
+    method public deprecated android.support.v4.app.NotificationCompat.WearableExtender setGravity(int);
     method public android.support.v4.app.NotificationCompat.WearableExtender setHintAmbientBigPicture(boolean);
-    method public android.support.v4.app.NotificationCompat.WearableExtender setHintAvoidBackgroundClipping(boolean);
+    method public deprecated android.support.v4.app.NotificationCompat.WearableExtender setHintAvoidBackgroundClipping(boolean);
     method public android.support.v4.app.NotificationCompat.WearableExtender setHintContentIntentLaunchesActivity(boolean);
-    method public android.support.v4.app.NotificationCompat.WearableExtender setHintHideIcon(boolean);
-    method public android.support.v4.app.NotificationCompat.WearableExtender setHintScreenTimeout(int);
-    method public android.support.v4.app.NotificationCompat.WearableExtender setHintShowBackgroundOnly(boolean);
+    method public deprecated android.support.v4.app.NotificationCompat.WearableExtender setHintHideIcon(boolean);
+    method public deprecated android.support.v4.app.NotificationCompat.WearableExtender setHintScreenTimeout(int);
+    method public deprecated android.support.v4.app.NotificationCompat.WearableExtender setHintShowBackgroundOnly(boolean);
     method public android.support.v4.app.NotificationCompat.WearableExtender setStartScrollBottom(boolean);
     field public static final int SCREEN_TIMEOUT_LONG = -1; // 0xffffffff
     field public static final int SCREEN_TIMEOUT_SHORT = 0; // 0x0
@@ -682,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 {
@@ -710,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";
@@ -717,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 {
   }
 
@@ -805,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);
   }
@@ -844,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 {
@@ -891,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 {
@@ -1123,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();
@@ -1173,83 +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 boolean isEmpty();
-    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...);
@@ -1288,49 +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 boolean isEmpty();
-    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 {
@@ -1562,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);
@@ -1581,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);
   }
@@ -2029,6 +2060,7 @@
     method public int getDrawingOrder();
     method public java.lang.CharSequence getError();
     method public android.os.Bundle getExtras();
+    method public java.lang.CharSequence getHintText();
     method public deprecated java.lang.Object getInfo();
     method public int getInputType();
     method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getLabelFor();
@@ -2037,12 +2069,14 @@
     method public int getMaxTextLength();
     method public int getMovementGranularities();
     method public java.lang.CharSequence getPackageName();
+    method public java.lang.CharSequence getPaneTitle();
     method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getParent();
     method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat getRangeInfo();
     method public java.lang.CharSequence getRoleDescription();
     method public java.lang.CharSequence getText();
     method public int getTextSelectionEnd();
     method public int getTextSelectionStart();
+    method public java.lang.CharSequence getTooltipText();
     method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getTraversalAfter();
     method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getTraversalBefore();
     method public java.lang.String getViewIdResourceName();
@@ -2059,12 +2093,15 @@
     method public boolean isEnabled();
     method public boolean isFocusable();
     method public boolean isFocused();
+    method public boolean isHeading();
     method public boolean isImportantForAccessibility();
     method public boolean isLongClickable();
     method public boolean isMultiLine();
     method public boolean isPassword();
+    method public boolean isScreenReaderFocusable();
     method public boolean isScrollable();
     method public boolean isSelected();
+    method public boolean isShowingHintText();
     method public boolean isVisibleToUser();
     method public static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat obtain(android.view.View);
     method public static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat obtain(android.view.View, int);
@@ -2097,6 +2134,8 @@
     method public void setError(java.lang.CharSequence);
     method public void setFocusable(boolean);
     method public void setFocused(boolean);
+    method public void setHeading(boolean);
+    method public void setHintText(java.lang.CharSequence);
     method public void setImportantForAccessibility(boolean);
     method public void setInputType(int);
     method public void setLabelFor(android.view.View);
@@ -2109,17 +2148,21 @@
     method public void setMovementGranularities(int);
     method public void setMultiLine(boolean);
     method public void setPackageName(java.lang.CharSequence);
+    method public void setPaneTitle(java.lang.CharSequence);
     method public void setParent(android.view.View);
     method public void setParent(android.view.View, int);
     method public void setPassword(boolean);
     method public void setRangeInfo(android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat);
     method public void setRoleDescription(java.lang.CharSequence);
+    method public void setScreenReaderFocusable(boolean);
     method public void setScrollable(boolean);
     method public void setSelected(boolean);
+    method public void setShowingHintText(boolean);
     method public void setSource(android.view.View);
     method public void setSource(android.view.View, int);
     method public void setText(java.lang.CharSequence);
     method public void setTextSelection(int, int);
+    method public void setTooltipText(java.lang.CharSequence);
     method public void setTraversalAfter(android.view.View);
     method public void setTraversalAfter(android.view.View, int);
     method public void setTraversalBefore(android.view.View);
@@ -2133,6 +2176,8 @@
     field public static final java.lang.String ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN = "ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN";
     field public static final java.lang.String ACTION_ARGUMENT_HTML_ELEMENT_STRING = "ACTION_ARGUMENT_HTML_ELEMENT_STRING";
     field public static final java.lang.String ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT = "ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT";
+    field public static final java.lang.String ACTION_ARGUMENT_MOVE_WINDOW_X = "ACTION_ARGUMENT_MOVE_WINDOW_X";
+    field public static final java.lang.String ACTION_ARGUMENT_MOVE_WINDOW_Y = "ACTION_ARGUMENT_MOVE_WINDOW_Y";
     field public static final java.lang.String ACTION_ARGUMENT_PROGRESS_VALUE = "android.view.accessibility.action.ARGUMENT_PROGRESS_VALUE";
     field public static final java.lang.String ACTION_ARGUMENT_ROW_INT = "android.view.accessibility.action.ARGUMENT_ROW_INT";
     field public static final java.lang.String ACTION_ARGUMENT_SELECTION_END_INT = "ACTION_ARGUMENT_SELECTION_END_INT";
@@ -2184,7 +2229,9 @@
     field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_DISMISS;
     field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_EXPAND;
     field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_FOCUS;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_HIDE_TOOLTIP;
     field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_LONG_CLICK;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_MOVE_WINDOW;
     field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_NEXT_AT_MOVEMENT_GRANULARITY;
     field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_NEXT_HTML_ELEMENT;
     field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PASTE;
@@ -2202,6 +2249,7 @@
     field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_SET_SELECTION;
     field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_SET_TEXT;
     field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_SHOW_ON_SCREEN;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_SHOW_TOOLTIP;
   }
 
   public static class AccessibilityNodeInfoCompat.CollectionInfoCompat {
@@ -2345,6 +2393,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);
@@ -2353,6 +2428,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);
@@ -2378,11 +2462,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/values-af/strings.xml b/compat/res/values-af/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-af/strings.xml
+++ b/compat/res/values-af/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-am/strings.xml b/compat/res/values-am/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-am/strings.xml
+++ b/compat/res/values-am/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-ar/strings.xml b/compat/res/values-ar/strings.xml
index d9094fb..f544aef 100644
--- a/compat/res/values-ar/strings.xml
+++ b/compat/res/values-ar/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"+999"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-az/strings.xml b/compat/res/values-az/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-az/strings.xml
+++ b/compat/res/values-az/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-b+sr+Latn/strings.xml b/compat/res/values-b+sr+Latn/strings.xml
index df46d35..f544aef 100644
--- a/compat/res/values-b+sr+Latn/strings.xml
+++ b/compat/res/values-b+sr+Latn/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"&gt;999"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-be/strings.xml b/compat/res/values-be/strings.xml
index ae35194..f544aef 100644
--- a/compat/res/values-be/strings.xml
+++ b/compat/res/values-be/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"больш за 999"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-bg/strings.xml b/compat/res/values-bg/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-bg/strings.xml
+++ b/compat/res/values-bg/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-bn/strings.xml b/compat/res/values-bn/strings.xml
index 01516f8..b9c349e 100644
--- a/compat/res/values-bn/strings.xml
+++ b/compat/res/values-bn/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"৯৯৯+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"৯৯৯+"</string>
 </resources>
diff --git a/compat/res/values-bs/strings.xml b/compat/res/values-bs/strings.xml
index df46d35..f544aef 100644
--- a/compat/res/values-bs/strings.xml
+++ b/compat/res/values-bs/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"&gt;999"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-ca/strings.xml b/compat/res/values-ca/strings.xml
index d9094fb..f544aef 100644
--- a/compat/res/values-ca/strings.xml
+++ b/compat/res/values-ca/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"+999"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-cs/strings.xml b/compat/res/values-cs/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-cs/strings.xml
+++ b/compat/res/values-cs/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-da/strings.xml b/compat/res/values-da/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-da/strings.xml
+++ b/compat/res/values-da/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-de/strings.xml b/compat/res/values-de/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-de/strings.xml
+++ b/compat/res/values-de/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-el/strings.xml b/compat/res/values-el/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-el/strings.xml
+++ b/compat/res/values-el/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-en-rAU/strings.xml b/compat/res/values-en-rAU/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-en-rAU/strings.xml
+++ b/compat/res/values-en-rAU/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-en-rCA/strings.xml b/compat/res/values-en-rCA/strings.xml
new file mode 100644
index 0000000..f544aef
--- /dev/null
+++ b/compat/res/values-en-rCA/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
+</resources>
diff --git a/compat/res/values-en-rGB/strings.xml b/compat/res/values-en-rGB/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-en-rGB/strings.xml
+++ b/compat/res/values-en-rGB/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-en-rIN/strings.xml b/compat/res/values-en-rIN/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-en-rIN/strings.xml
+++ b/compat/res/values-en-rIN/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-en-rXC/strings.xml b/compat/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000..95175c2
--- /dev/null
+++ b/compat/res/values-en-rXC/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‏‎‏‏‏‎‏‏‎‎‎‎‏‎‏‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‏‎‏‏‏‎‎‏‎‏‏‏‎‏‏‏‏‏‏‏‎‎‎‏‏‎999+‎‏‎‎‏‎"</string>
+</resources>
diff --git a/compat/res/values-es-rUS/strings.xml b/compat/res/values-es-rUS/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-es-rUS/strings.xml
+++ b/compat/res/values-es-rUS/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-es/strings.xml b/compat/res/values-es/strings.xml
index d9094fb..3a0ae16 100644
--- a/compat/res/values-es/strings.xml
+++ b/compat/res/values-es/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"+999"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"+999"</string>
 </resources>
diff --git a/compat/res/values-et/strings.xml b/compat/res/values-et/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-et/strings.xml
+++ b/compat/res/values-et/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-eu/strings.xml b/compat/res/values-eu/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-eu/strings.xml
+++ b/compat/res/values-eu/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-fa/strings.xml b/compat/res/values-fa/strings.xml
index 0470999..f544aef 100644
--- a/compat/res/values-fa/strings.xml
+++ b/compat/res/values-fa/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"۹۹۹+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-fi/strings.xml b/compat/res/values-fi/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-fi/strings.xml
+++ b/compat/res/values-fi/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-fr-rCA/strings.xml b/compat/res/values-fr-rCA/strings.xml
index df46d35..f544aef 100644
--- a/compat/res/values-fr-rCA/strings.xml
+++ b/compat/res/values-fr-rCA/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"&gt;999"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-fr/strings.xml b/compat/res/values-fr/strings.xml
index df46d35..f544aef 100644
--- a/compat/res/values-fr/strings.xml
+++ b/compat/res/values-fr/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"&gt;999"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-gl/strings.xml b/compat/res/values-gl/strings.xml
index df46d35..9ac8ff5 100644
--- a/compat/res/values-gl/strings.xml
+++ b/compat/res/values-gl/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"&gt;999"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"&gt;999"</string>
 </resources>
diff --git a/compat/res/values-gu/strings.xml b/compat/res/values-gu/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-gu/strings.xml
+++ b/compat/res/values-gu/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-hi/strings.xml b/compat/res/values-hi/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-hi/strings.xml
+++ b/compat/res/values-hi/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-hr/strings.xml b/compat/res/values-hr/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-hr/strings.xml
+++ b/compat/res/values-hr/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-hu/strings.xml b/compat/res/values-hu/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-hu/strings.xml
+++ b/compat/res/values-hu/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-hy/strings.xml b/compat/res/values-hy/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-hy/strings.xml
+++ b/compat/res/values-hy/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-in/strings.xml b/compat/res/values-in/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-in/strings.xml
+++ b/compat/res/values-in/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-is/strings.xml b/compat/res/values-is/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-is/strings.xml
+++ b/compat/res/values-is/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-it/strings.xml b/compat/res/values-it/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-it/strings.xml
+++ b/compat/res/values-it/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-iw/strings.xml b/compat/res/values-iw/strings.xml
index 6799e67..f544aef 100644
--- a/compat/res/values-iw/strings.xml
+++ b/compat/res/values-iw/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"‎999+‎"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-ja/strings.xml b/compat/res/values-ja/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-ja/strings.xml
+++ b/compat/res/values-ja/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-ka/strings.xml b/compat/res/values-ka/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-ka/strings.xml
+++ b/compat/res/values-ka/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-kk/strings.xml b/compat/res/values-kk/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-kk/strings.xml
+++ b/compat/res/values-kk/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-km/strings.xml b/compat/res/values-km/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-km/strings.xml
+++ b/compat/res/values-km/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-kn/strings.xml b/compat/res/values-kn/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-kn/strings.xml
+++ b/compat/res/values-kn/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-ko/strings.xml b/compat/res/values-ko/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-ko/strings.xml
+++ b/compat/res/values-ko/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-ky/strings.xml b/compat/res/values-ky/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-ky/strings.xml
+++ b/compat/res/values-ky/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-lo/strings.xml b/compat/res/values-lo/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-lo/strings.xml
+++ b/compat/res/values-lo/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-lt/strings.xml b/compat/res/values-lt/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-lt/strings.xml
+++ b/compat/res/values-lt/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-lv/strings.xml b/compat/res/values-lv/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-lv/strings.xml
+++ b/compat/res/values-lv/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-mk/strings.xml b/compat/res/values-mk/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-mk/strings.xml
+++ b/compat/res/values-mk/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-ml/strings.xml b/compat/res/values-ml/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-ml/strings.xml
+++ b/compat/res/values-ml/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-mn/strings.xml b/compat/res/values-mn/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-mn/strings.xml
+++ b/compat/res/values-mn/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-mr/strings.xml b/compat/res/values-mr/strings.xml
index 4640923..9e05b34 100644
--- a/compat/res/values-mr/strings.xml
+++ b/compat/res/values-mr/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"९९९+"</string>
 </resources>
diff --git a/compat/res/values-ms/strings.xml b/compat/res/values-ms/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-ms/strings.xml
+++ b/compat/res/values-ms/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-my/strings.xml b/compat/res/values-my/strings.xml
index cfad64a..327c469 100644
--- a/compat/res/values-my/strings.xml
+++ b/compat/res/values-my/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"၉၉၉+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"၉၉၉+"</string>
 </resources>
diff --git a/compat/res/values-nb/strings.xml b/compat/res/values-nb/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-nb/strings.xml
+++ b/compat/res/values-nb/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-ne/strings.xml b/compat/res/values-ne/strings.xml
index 3dd1d09..9e05b34 100644
--- a/compat/res/values-ne/strings.xml
+++ b/compat/res/values-ne/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"९९९+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"९९९+"</string>
 </resources>
diff --git a/compat/res/values-nl/strings.xml b/compat/res/values-nl/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-nl/strings.xml
+++ b/compat/res/values-nl/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-pa/strings.xml b/compat/res/values-pa/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-pa/strings.xml
+++ b/compat/res/values-pa/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-pl/strings.xml b/compat/res/values-pl/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-pl/strings.xml
+++ b/compat/res/values-pl/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-pt-rBR/strings.xml b/compat/res/values-pt-rBR/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-pt-rBR/strings.xml
+++ b/compat/res/values-pt-rBR/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-pt-rPT/strings.xml b/compat/res/values-pt-rPT/strings.xml
index d9094fb..f544aef 100644
--- a/compat/res/values-pt-rPT/strings.xml
+++ b/compat/res/values-pt-rPT/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"+999"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-pt/strings.xml b/compat/res/values-pt/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-pt/strings.xml
+++ b/compat/res/values-pt/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-ro/strings.xml b/compat/res/values-ro/strings.xml
index 42598dc..f544aef 100644
--- a/compat/res/values-ro/strings.xml
+++ b/compat/res/values-ro/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"˃999"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-ru/strings.xml b/compat/res/values-ru/strings.xml
index df46d35..f544aef 100644
--- a/compat/res/values-ru/strings.xml
+++ b/compat/res/values-ru/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"&gt;999"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-si/strings.xml b/compat/res/values-si/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-si/strings.xml
+++ b/compat/res/values-si/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-sk/strings.xml b/compat/res/values-sk/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-sk/strings.xml
+++ b/compat/res/values-sk/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-sl/strings.xml b/compat/res/values-sl/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-sl/strings.xml
+++ b/compat/res/values-sl/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-sq/strings.xml b/compat/res/values-sq/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-sq/strings.xml
+++ b/compat/res/values-sq/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-sr/strings.xml b/compat/res/values-sr/strings.xml
index df46d35..f544aef 100644
--- a/compat/res/values-sr/strings.xml
+++ b/compat/res/values-sr/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"&gt;999"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-sv/strings.xml b/compat/res/values-sv/strings.xml
index df46d35..f544aef 100644
--- a/compat/res/values-sv/strings.xml
+++ b/compat/res/values-sv/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"&gt;999"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-sw/strings.xml b/compat/res/values-sw/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-sw/strings.xml
+++ b/compat/res/values-sw/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-ta/strings.xml b/compat/res/values-ta/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-ta/strings.xml
+++ b/compat/res/values-ta/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-te/strings.xml b/compat/res/values-te/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-te/strings.xml
+++ b/compat/res/values-te/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-th/strings.xml b/compat/res/values-th/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-th/strings.xml
+++ b/compat/res/values-th/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-tl/strings.xml b/compat/res/values-tl/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-tl/strings.xml
+++ b/compat/res/values-tl/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-tr/strings.xml b/compat/res/values-tr/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-tr/strings.xml
+++ b/compat/res/values-tr/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-uk/strings.xml b/compat/res/values-uk/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-uk/strings.xml
+++ b/compat/res/values-uk/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-ur/strings.xml b/compat/res/values-ur/strings.xml
index 6799e67..3a0ae16 100644
--- a/compat/res/values-ur/strings.xml
+++ b/compat/res/values-ur/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"‎999+‎"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"+999"</string>
 </resources>
diff --git a/compat/res/values-uz/strings.xml b/compat/res/values-uz/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-uz/strings.xml
+++ b/compat/res/values-uz/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-vi/strings.xml b/compat/res/values-vi/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-vi/strings.xml
+++ b/compat/res/values-vi/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-zh-rCN/strings.xml b/compat/res/values-zh-rCN/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-zh-rCN/strings.xml
+++ b/compat/res/values-zh-rCN/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-zh-rHK/strings.xml b/compat/res/values-zh-rHK/strings.xml
index d509360..f544aef 100644
--- a/compat/res/values-zh-rHK/strings.xml
+++ b/compat/res/values-zh-rHK/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999 +"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-zh-rTW/strings.xml b/compat/res/values-zh-rTW/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-zh-rTW/strings.xml
+++ b/compat/res/values-zh-rTW/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </resources>
diff --git a/compat/res/values-zu/strings.xml b/compat/res/values-zu/strings.xml
index 4640923..f544aef 100644
--- a/compat/res/values-zu/strings.xml
+++ b/compat/res/values-zu/strings.xml
@@ -1,5 +1,5 @@
 <?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");
@@ -13,9 +13,9 @@
   ~ WITHOUT 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="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="status_bar_notification_info_overflow" msgid="7988687684186075107">"999+"</string>
 </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/tests/java/android/support/v4/app/NotificationCompatTest.java b/compat/src/androidTest/java/android/support/v4/app/NotificationCompatTest.java
similarity index 100%
rename from compat/tests/java/android/support/v4/app/NotificationCompatTest.java
rename to compat/src/androidTest/java/android/support/v4/app/NotificationCompatTest.java
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/src/androidTest/java/android/support/v4/content/ContextCompatTest.java b/compat/src/androidTest/java/android/support/v4/content/ContextCompatTest.java
new file mode 100644
index 0000000..31d6b2c
--- /dev/null
+++ b/compat/src/androidTest/java/android/support/v4/content/ContextCompatTest.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 static org.junit.Assert.assertEquals;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.ColorStateList;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.support.compat.test.R;
+import android.support.test.filters.SmallTest;
+import android.support.v4.BaseInstrumentationTestCase;
+import android.support.v4.ThemedYellowActivity;
+import android.support.v4.testutils.TestUtils;
+import android.util.DisplayMetrics;
+
+import org.junit.Before;
+import org.junit.Test;
+
+@SmallTest
+public class ContextCompatTest extends BaseInstrumentationTestCase<ThemedYellowActivity> {
+    private Context mContext;
+
+    public ContextCompatTest() {
+        super(ThemedYellowActivity.class);
+    }
+
+    @Before
+    public void setup() {
+        mContext = mActivityTestRule.getActivity();
+    }
+
+    @Test
+    public void testGetColor() throws Throwable {
+        assertEquals("Unthemed color load", 0xFFFF8090,
+                ContextCompat.getColor(mContext, R.color.text_color));
+
+        if (Build.VERSION.SDK_INT >= 23) {
+            // The following test is only expected to pass on v23+ devices. The result of
+            // calling theme-aware getColor() in pre-v23 is undefined.
+            assertEquals("Themed yellow color load",
+                    ContextCompat.getColor(mContext, R.color.simple_themed_selector),
+                    0xFFF0B000);
+        }
+    }
+
+    @Test
+    public void testGetColorStateList() throws Throwable {
+        ColorStateList unthemedColorStateList =
+                ContextCompat.getColorStateList(mContext, R.color.complex_unthemed_selector);
+        assertEquals("Unthemed color state list load: default", 0xFF70A0C0,
+                unthemedColorStateList.getDefaultColor());
+        assertEquals("Unthemed color state list load: focused", 0xFF70B0F0,
+                unthemedColorStateList.getColorForState(
+                        new int[]{android.R.attr.state_focused}, 0));
+        assertEquals("Unthemed color state list load: pressed", 0xFF6080B0,
+                unthemedColorStateList.getColorForState(
+                        new int[]{android.R.attr.state_pressed}, 0));
+
+        if (Build.VERSION.SDK_INT >= 23) {
+            // The following tests are only expected to pass on v23+ devices. The result of
+            // calling theme-aware getColorStateList() in pre-v23 is undefined.
+            ColorStateList themedYellowColorStateList =
+                    ContextCompat.getColorStateList(mContext, R.color.complex_themed_selector);
+            assertEquals("Themed yellow color state list load: default", 0xFFF0B000,
+                    themedYellowColorStateList.getDefaultColor());
+            assertEquals("Themed yellow color state list load: focused", 0xFFF0A020,
+                    themedYellowColorStateList.getColorForState(
+                            new int[]{android.R.attr.state_focused}, 0));
+            assertEquals("Themed yellow color state list load: pressed", 0xFFE0A040,
+                    themedYellowColorStateList.getColorForState(
+                            new int[]{android.R.attr.state_pressed}, 0));
+        }
+    }
+
+    @Test
+    public void testGetDrawable() throws Throwable {
+        Drawable unthemedDrawable =
+                ContextCompat.getDrawable(mContext, R.drawable.test_drawable_red);
+        TestUtils.assertAllPixelsOfColor("Unthemed drawable load",
+                unthemedDrawable, mContext.getResources().getColor(R.color.test_red));
+
+        if (Build.VERSION.SDK_INT >= 23) {
+            // The following test is only expected to pass on v23+ devices. The result of
+            // calling theme-aware getDrawable() in pre-v23 is undefined.
+            Drawable themedYellowDrawable =
+                    ContextCompat.getDrawable(mContext, R.drawable.themed_drawable);
+            TestUtils.assertAllPixelsOfColor("Themed yellow drawable load",
+                    themedYellowDrawable, 0xFFF0B000);
+        }
+    }
+
+    @Test
+    public void testDrawableConfigurationWorkaround() throws Throwable {
+        final int expectedWidth = scaleFromDensity(7, DisplayMetrics.DENSITY_LOW,
+                mContext.getResources().getDisplayMetrics().densityDpi);
+
+        // Ensure we retrieve the correct drawable configuration. Specifically,
+        // this tests a workaround for a bug in drawable configuration that
+        // exists on API < 16 for references to drawables.
+        Drawable referencedDrawable = ContextCompat.getDrawable(mContext,
+                R.drawable.aliased_drawable);
+        assertEquals("Drawable configuration does not match DisplayMetrics",
+                expectedWidth, referencedDrawable.getIntrinsicWidth());
+    }
+
+    private static int scaleFromDensity(int size, int sdensity, int tdensity) {
+        if (sdensity == tdensity) {
+            return size;
+        }
+
+        // Scale by tdensity / sdensity, rounding up.
+        return ((size * tdensity) + (sdensity >> 1)) / sdensity;
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testCheckSelfPermissionNull() {
+        ContextCompat.checkSelfPermission(mContext, null);
+    }
+
+    @Test
+    public void testCheckSelfPermission() {
+        assertEquals("Vibrate permission granted", PackageManager.PERMISSION_GRANTED,
+                ContextCompat.checkSelfPermission(mContext,
+                        android.Manifest.permission.VIBRATE));
+        assertEquals("Wake lock permission granted", PackageManager.PERMISSION_GRANTED,
+                ContextCompat.checkSelfPermission(mContext,
+                        android.Manifest.permission.WAKE_LOCK));
+
+        // The following permissions (normal and dangerous) are expected to be denied as they are
+        // not declared in our manifest.
+        assertEquals("Access network state permission denied", PackageManager.PERMISSION_DENIED,
+                ContextCompat.checkSelfPermission(mContext,
+                        android.Manifest.permission.ACCESS_NETWORK_STATE));
+        assertEquals("Bluetooth permission denied", PackageManager.PERMISSION_DENIED,
+                ContextCompat.checkSelfPermission(mContext,
+                        android.Manifest.permission.BLUETOOTH));
+        assertEquals("Call phone permission denied", PackageManager.PERMISSION_DENIED,
+                ContextCompat.checkSelfPermission(mContext,
+                        android.Manifest.permission.CALL_PHONE));
+        assertEquals("Delete packages permission denied", PackageManager.PERMISSION_DENIED,
+                ContextCompat.checkSelfPermission(mContext,
+                        android.Manifest.permission.DELETE_PACKAGES));
+    }
+}
\ No newline at end of file
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/tests/java/android/support/v4/content/res/FontResourcesParserCompatTest.java b/compat/src/androidTest/java/android/support/v4/content/res/FontResourcesParserCompatTest.java
similarity index 100%
rename from compat/tests/java/android/support/v4/content/res/FontResourcesParserCompatTest.java
rename to compat/src/androidTest/java/android/support/v4/content/res/FontResourcesParserCompatTest.java
diff --git a/compat/src/androidTest/java/android/support/v4/content/res/ResourcesCompatTest.java b/compat/src/androidTest/java/android/support/v4/content/res/ResourcesCompatTest.java
new file mode 100644
index 0000000..b326dd6
--- /dev/null
+++ b/compat/src/androidTest/java/android/support/v4/content/res/ResourcesCompatTest.java
@@ -0,0 +1,425 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 org.junit.Assert.assertEquals;
+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 android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.Resources;
+import android.graphics.Typeface;
+import android.graphics.drawable.Drawable;
+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.provider.FontsContractCompat;
+import android.support.v4.provider.MockFontProvider;
+import android.support.v4.testutils.TestUtils;
+import android.util.DisplayMetrics;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@SmallTest
+public class ResourcesCompatTest {
+    private Context mContext;
+    private Resources mResources;
+
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getContext();
+        mResources = mContext.getResources();
+        MockFontProvider.prepareFontFiles(mContext);
+    }
+
+    @Test
+    public void testGetColor() throws Throwable {
+        assertEquals("Unthemed color load",
+                ResourcesCompat.getColor(mResources, R.color.text_color, null),
+                0xFFFF8090);
+
+        if (Build.VERSION.SDK_INT >= 23) {
+            // The following tests are only expected to pass on v23+ devices. The result of
+            // calling theme-aware getColor() in pre-v23 is undefined.
+            final Resources.Theme yellowTheme = mResources.newTheme();
+            yellowTheme.applyStyle(R.style.YellowTheme, true);
+            assertEquals("Themed yellow color load", 0xFFF0B000,
+                    ResourcesCompat.getColor(mResources, R.color.simple_themed_selector,
+                            yellowTheme));
+
+            final Resources.Theme lilacTheme = mResources.newTheme();
+            lilacTheme.applyStyle(R.style.LilacTheme, true);
+            assertEquals("Themed lilac color load", 0xFFF080F0,
+                    ResourcesCompat.getColor(mResources, R.color.simple_themed_selector,
+                            lilacTheme));
+        }
+    }
+
+    @Test
+    public void testGetColorStateList() throws Throwable {
+        final ColorStateList unthemedColorStateList =
+                ResourcesCompat.getColorStateList(mResources, R.color.complex_unthemed_selector,
+                        null);
+        assertEquals("Unthemed color state list load: default", 0xFF70A0C0,
+                unthemedColorStateList.getDefaultColor());
+        assertEquals("Unthemed color state list load: focused", 0xFF70B0F0,
+                unthemedColorStateList.getColorForState(
+                        new int[]{android.R.attr.state_focused}, 0));
+        assertEquals("Unthemed color state list load: pressed", 0xFF6080B0,
+                unthemedColorStateList.getColorForState(
+                        new int[]{android.R.attr.state_pressed}, 0));
+
+        if (Build.VERSION.SDK_INT >= 23) {
+            // The following tests are only expected to pass on v23+ devices. The result of
+            // calling theme-aware getColorStateList() in pre-v23 is undefined.
+            final Resources.Theme yellowTheme = mResources.newTheme();
+            yellowTheme.applyStyle(R.style.YellowTheme, true);
+            final ColorStateList themedYellowColorStateList =
+                    ResourcesCompat.getColorStateList(mResources, R.color.complex_themed_selector,
+                            yellowTheme);
+            assertEquals("Themed yellow color state list load: default", 0xFFF0B000,
+                    themedYellowColorStateList.getDefaultColor());
+            assertEquals("Themed yellow color state list load: focused", 0xFFF0A020,
+                    themedYellowColorStateList.getColorForState(
+                            new int[]{android.R.attr.state_focused}, 0));
+            assertEquals("Themed yellow color state list load: pressed", 0xFFE0A040,
+                    themedYellowColorStateList.getColorForState(
+                            new int[]{android.R.attr.state_pressed}, 0));
+
+            final Resources.Theme lilacTheme = mResources.newTheme();
+            lilacTheme.applyStyle(R.style.LilacTheme, true);
+            final ColorStateList themedLilacColorStateList =
+                    ResourcesCompat.getColorStateList(mResources, R.color.complex_themed_selector,
+                            lilacTheme);
+            assertEquals("Themed lilac color state list load: default", 0xFFF080F0,
+                    themedLilacColorStateList.getDefaultColor());
+            assertEquals("Themed lilac color state list load: focused", 0xFFF070D0,
+                    themedLilacColorStateList.getColorForState(
+                            new int[]{android.R.attr.state_focused}, 0));
+            assertEquals("Themed lilac color state list load: pressed", 0xFFE070A0,
+                    themedLilacColorStateList.getColorForState(
+                            new int[]{android.R.attr.state_pressed}, 0));
+        }
+    }
+
+    @Test
+    public void testGetDrawable() throws Throwable {
+        final Drawable unthemedDrawable =
+                ResourcesCompat.getDrawable(mResources, R.drawable.test_drawable_red, null);
+        TestUtils.assertAllPixelsOfColor("Unthemed drawable load",
+                unthemedDrawable, mResources.getColor(R.color.test_red));
+
+        if (Build.VERSION.SDK_INT >= 23) {
+            // The following tests are only expected to pass on v23+ devices. The result of
+            // calling theme-aware getDrawable() in pre-v23 is undefined.
+            final Resources.Theme yellowTheme = mResources.newTheme();
+            yellowTheme.applyStyle(R.style.YellowTheme, true);
+            final Drawable themedYellowDrawable =
+                    ResourcesCompat.getDrawable(mResources, R.drawable.themed_drawable,
+                            yellowTheme);
+            TestUtils.assertAllPixelsOfColor("Themed yellow drawable load",
+                    themedYellowDrawable, 0xFFF0B000);
+
+            final Resources.Theme lilacTheme = mResources.newTheme();
+            lilacTheme.applyStyle(R.style.LilacTheme, true);
+            final Drawable themedLilacDrawable =
+                    ResourcesCompat.getDrawable(mResources, R.drawable.themed_drawable, lilacTheme);
+            TestUtils.assertAllPixelsOfColor("Themed lilac drawable load",
+                    themedLilacDrawable, 0xFFF080F0);
+        }
+    }
+
+    @Test
+    public void testGetDrawableForDensityUnthemed() throws Throwable {
+        // Density-aware drawable loading for now only works on raw bitmap drawables.
+
+        // Different variants of density_aware_drawable are set up in the following way:
+        //    mdpi - 12x12 px which is 12x12 dip
+        //    hdpi - 21x21 px which is 14x14 dip
+        //   xhdpi - 32x32 px which is 16x16 dip
+        //  xxhdpi - 54x54 px which is 18x18 dip
+        // The tests below (on v15+ devices) are checking that an unthemed density-aware
+        // loading of raw bitmap drawables returns a drawable with matching intrinsic
+        // dimensions.
+
+        final Drawable unthemedDrawableForMediumDensity =
+                ResourcesCompat.getDrawableForDensity(mResources, R.drawable.density_aware_drawable,
+                        DisplayMetrics.DENSITY_MEDIUM, null);
+        // For pre-v15 devices we should get a drawable that corresponds to the density of the
+        // current device. For v15+ devices we should get a drawable that corresponds to the
+        // density requested in the API call.
+        final int expectedSizeForMediumDensity = (Build.VERSION.SDK_INT < 15) ?
+                mResources.getDimensionPixelSize(R.dimen.density_aware_size) : 12;
+        assertEquals("Unthemed density-aware drawable load: medium width",
+                expectedSizeForMediumDensity, unthemedDrawableForMediumDensity.getIntrinsicWidth());
+        assertEquals("Unthemed density-aware drawable load: medium height",
+                expectedSizeForMediumDensity,
+                unthemedDrawableForMediumDensity.getIntrinsicHeight());
+
+        final Drawable unthemedDrawableForHighDensity =
+                ResourcesCompat.getDrawableForDensity(mResources, R.drawable.density_aware_drawable,
+                        DisplayMetrics.DENSITY_HIGH, null);
+        // For pre-v15 devices we should get a drawable that corresponds to the density of the
+        // current device. For v15+ devices we should get a drawable that corresponds to the
+        // density requested in the API call.
+        final int expectedSizeForHighDensity = (Build.VERSION.SDK_INT < 15) ?
+                mResources.getDimensionPixelSize(R.dimen.density_aware_size) : 21;
+        assertEquals("Unthemed density-aware drawable load: high width",
+                expectedSizeForHighDensity, unthemedDrawableForHighDensity.getIntrinsicWidth());
+        assertEquals("Unthemed density-aware drawable load: high height",
+                expectedSizeForHighDensity, unthemedDrawableForHighDensity.getIntrinsicHeight());
+
+        final Drawable unthemedDrawableForXHighDensity =
+                ResourcesCompat.getDrawableForDensity(mResources, R.drawable.density_aware_drawable,
+                        DisplayMetrics.DENSITY_XHIGH, null);
+        // For pre-v15 devices we should get a drawable that corresponds to the density of the
+        // current device. For v15+ devices we should get a drawable that corresponds to the
+        // density requested in the API call.
+        final int expectedSizeForXHighDensity = (Build.VERSION.SDK_INT < 15) ?
+                mResources.getDimensionPixelSize(R.dimen.density_aware_size) : 32;
+        assertEquals("Unthemed density-aware drawable load: xhigh width",
+                expectedSizeForXHighDensity, unthemedDrawableForXHighDensity.getIntrinsicWidth());
+        assertEquals("Unthemed density-aware drawable load: xhigh height",
+                expectedSizeForXHighDensity, unthemedDrawableForXHighDensity.getIntrinsicHeight());
+
+        final Drawable unthemedDrawableForXXHighDensity =
+                ResourcesCompat.getDrawableForDensity(mResources, R.drawable.density_aware_drawable,
+                        DisplayMetrics.DENSITY_XXHIGH, null);
+        // For pre-v15 devices we should get a drawable that corresponds to the density of the
+        // current device. For v15+ devices we should get a drawable that corresponds to the
+        // density requested in the API call.
+        final int expectedSizeForXXHighDensity = (Build.VERSION.SDK_INT < 15) ?
+                mResources.getDimensionPixelSize(R.dimen.density_aware_size) : 54;
+        assertEquals("Unthemed density-aware drawable load: xxhigh width",
+                expectedSizeForXXHighDensity, unthemedDrawableForXXHighDensity.getIntrinsicWidth());
+        assertEquals("Unthemed density-aware drawable load: xxhigh height",
+                expectedSizeForXXHighDensity,
+                unthemedDrawableForXXHighDensity.getIntrinsicHeight());
+    }
+
+    @Test
+    public void testGetDrawableForDensityThemed() throws Throwable {
+        if (Build.VERSION.SDK_INT < 21) {
+            // The following tests are only expected to pass on v21+ devices. The result of
+            // calling theme-aware getDrawableForDensity() in pre-v21 is undefined.
+            return;
+        }
+
+        // Density- and theme-aware drawable loading for now only works partially. This test
+        // checks only for theming of a tinted bitmap XML drawable, but not correct scaling.
+
+        // Set up the two test themes, yellow and lilac.
+        final Resources.Theme yellowTheme = mResources.newTheme();
+        yellowTheme.applyStyle(R.style.YellowTheme, true);
+
+        final Resources.Theme lilacTheme = mResources.newTheme();
+        lilacTheme.applyStyle(R.style.LilacTheme, true);
+
+        Drawable themedYellowDrawableForMediumDensity =
+                ResourcesCompat.getDrawableForDensity(mResources, R.drawable.themed_bitmap,
+                        DisplayMetrics.DENSITY_MEDIUM, yellowTheme);
+        // We should get a drawable that corresponds to the theme requested in the API call.
+        TestUtils.assertAllPixelsOfColor("Themed yellow density-aware drawable load : medium color",
+                themedYellowDrawableForMediumDensity, 0xFFF0B000);
+
+        Drawable themedLilacDrawableForMediumDensity =
+                ResourcesCompat.getDrawableForDensity(mResources, R.drawable.themed_bitmap,
+                        DisplayMetrics.DENSITY_MEDIUM, lilacTheme);
+        // We should get a drawable that corresponds to the theme requested in the API call.
+        TestUtils.assertAllPixelsOfColor("Themed lilac density-aware drawable load : medium color",
+                themedLilacDrawableForMediumDensity, 0xFFF080F0);
+
+        Drawable themedYellowDrawableForHighDensity =
+                ResourcesCompat.getDrawableForDensity(mResources, R.drawable.themed_bitmap,
+                        DisplayMetrics.DENSITY_HIGH, yellowTheme);
+        // We should get a drawable that corresponds to the theme requested in the API call.
+        TestUtils.assertAllPixelsOfColor("Themed yellow density-aware drawable load : high color",
+                themedYellowDrawableForHighDensity, 0xFFF0B000);
+
+        Drawable themedLilacDrawableForHighDensity =
+                ResourcesCompat.getDrawableForDensity(mResources, R.drawable.themed_bitmap,
+                        DisplayMetrics.DENSITY_HIGH, lilacTheme);
+        // We should get a drawable that corresponds to the theme requested in the API call.
+        TestUtils.assertAllPixelsOfColor("Themed lilac density-aware drawable load : high color",
+                themedLilacDrawableForHighDensity, 0xFFF080F0);
+
+        Drawable themedYellowDrawableForXHighDensity =
+                ResourcesCompat.getDrawableForDensity(mResources, R.drawable.themed_bitmap,
+                        DisplayMetrics.DENSITY_XHIGH, yellowTheme);
+        // We should get a drawable that corresponds to the theme requested in the API call.
+        TestUtils.assertAllPixelsOfColor("Themed yellow density-aware drawable load : xhigh color",
+                themedYellowDrawableForXHighDensity, 0xFFF0B000);
+
+        Drawable themedLilacDrawableForXHighDensity =
+                ResourcesCompat.getDrawableForDensity(mResources, R.drawable.themed_bitmap,
+                        DisplayMetrics.DENSITY_XHIGH, lilacTheme);
+        // We should get a drawable that corresponds to the theme requested in the API call.
+        TestUtils.assertAllPixelsOfColor("Themed lilac density-aware drawable load : xhigh color",
+                themedLilacDrawableForXHighDensity, 0xFFF080F0);
+
+        Drawable themedYellowDrawableForXXHighDensity =
+                ResourcesCompat.getDrawableForDensity(mResources, R.drawable.themed_bitmap,
+                        DisplayMetrics.DENSITY_XXHIGH, yellowTheme);
+        // We should get a drawable that corresponds to the theme requested in the API call.
+        TestUtils.assertAllPixelsOfColor("Themed yellow density-aware drawable load : xxhigh color",
+                themedYellowDrawableForXXHighDensity, 0xFFF0B000);
+
+        Drawable themedLilacDrawableForXXHighDensity =
+                ResourcesCompat.getDrawableForDensity(mResources, R.drawable.themed_bitmap,
+                        DisplayMetrics.DENSITY_XXHIGH, lilacTheme);
+        // We should get a drawable that corresponds to the theme requested in the API call.
+        TestUtils.assertAllPixelsOfColor("Themed lilac density-aware drawable load : xxhigh color",
+                themedLilacDrawableForXXHighDensity, 0xFFF080F0);
+    }
+
+    @Test(expected = Resources.NotFoundException.class)
+    public void testGetFont_invalidResourceId() {
+        ResourcesCompat.getFont(mContext, -1);
+    }
+
+    @Test
+    public void testGetFont_fontFile_sync() {
+        Typeface font = ResourcesCompat.getFont(mContext, R.font.samplefont);
+
+        assertNotNull(font);
+        assertNotSame(Typeface.DEFAULT, font);
+    }
+
+    private static final 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 testGetFont_fontFile_async() throws InterruptedException {
+        final CountDownLatch latch = new CountDownLatch(1);
+        final FontCallback callback = new FontCallback(latch);
+        FontsContractCompat.resetCache();
+
+        ResourcesCompat.getFont(mContext, R.font.samplefont, callback, null);
+
+        assertTrue(latch.await(5L, TimeUnit.SECONDS));
+
+        assertNotNull(callback.mTypeface);
+        assertNotSame(Typeface.DEFAULT, callback.mTypeface);
+    }
+
+    @Test
+    public void testGetFont_xmlFile_sync() {
+        Typeface font = ResourcesCompat.getFont(mContext, R.font.samplexmlfont);
+
+        assertNotNull(font);
+        assertNotSame(Typeface.DEFAULT, font);
+    }
+
+    @Test
+    public void testGetFont_xmlFile_async() throws InterruptedException {
+        final CountDownLatch latch = new CountDownLatch(1);
+        final FontCallback callback = new FontCallback(latch);
+
+        ResourcesCompat.getFont(mContext, R.font.samplexmlfont, callback, null);
+
+        assertTrue(latch.await(5L, TimeUnit.SECONDS));
+
+        assertNotNull(callback.mTypeface);
+        assertNotSame(Typeface.DEFAULT, callback.mTypeface);
+    }
+
+    @Test
+    public void testGetFont_xmlProviderFile_sync() {
+        Typeface font = ResourcesCompat.getFont(mContext, R.font.samplexmldownloadedfont);
+
+        assertNotNull(font);
+        assertNotSame(Typeface.DEFAULT, font);
+    }
+
+    @Test
+    public void testGetFont_xmlProviderFile_async() throws InterruptedException {
+        final CountDownLatch latch = new CountDownLatch(1);
+        final FontCallback callback = new FontCallback(latch);
+
+        // Font provider non-blocking requests post on the calling thread so can't run on
+        // the test thread as it doesn't have a Looper.
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                ResourcesCompat.getFont(mContext, R.font.samplexmldownloadedfont, callback, null);
+            }
+        });
+
+        assertTrue(latch.await(5L, TimeUnit.SECONDS));
+
+        assertNotNull(callback.mTypeface);
+        assertNotSame(Typeface.DEFAULT, callback.mTypeface);
+    }
+
+    @Test
+    public void testGetFont_invalidXmlFile() {
+        try {
+            assertNull(
+                    ResourcesCompat.getFont(mContext, R.font.invalid_xmlfamily));
+        } catch (Resources.NotFoundException e) {
+            // pass
+        }
+
+        try {
+            assertNull(ResourcesCompat.getFont(mContext, R.font.invalid_xmlempty));
+        } catch (Resources.NotFoundException e) {
+            // pass
+        }
+    }
+
+    @Test
+    public void testGetFont_fontFileIsCached() {
+        Typeface font = ResourcesCompat.getFont(mContext, R.font.samplefont);
+        Typeface font2 = ResourcesCompat.getFont(mContext, R.font.samplefont);
+
+        assertSame(font, font2);
+    }
+
+    @Test
+    public void testGetFont_xmlFileIsCached() {
+        Typeface font = ResourcesCompat.getFont(mContext, R.font.samplexmlfont);
+        Typeface font2 = ResourcesCompat.getFont(mContext, R.font.samplexmlfont);
+
+        assertSame(font, font2);
+    }
+}
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/tests/java/android/support/v4/graphics/TypefaceCompatTest.java b/compat/src/androidTest/java/android/support/v4/graphics/TypefaceCompatTest.java
similarity index 100%
rename from compat/tests/java/android/support/v4/graphics/TypefaceCompatTest.java
rename to compat/src/androidTest/java/android/support/v4/graphics/TypefaceCompatTest.java
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..329568d
--- /dev/null
+++ b/compat/src/androidTest/java/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatTest.java
@@ -0,0 +1,105 @@
+/*
+ * 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.hamcrest.CoreMatchers.is;
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assume.assumeTrue;
+
+import android.os.Build;
+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 {
+        AccessibilityNodeInfoCompat accessibilityNodeInfoCompat = obtainedWrappedNodeCompat();
+        accessibilityNodeInfoCompat.setCollectionInfo(null);
+    }
+
+    @Test
+    public void testSetCollectionItemInfoIsNullable() throws Exception {
+        AccessibilityNodeInfoCompat accessibilityNodeInfoCompat = obtainedWrappedNodeCompat();
+        accessibilityNodeInfoCompat.setCollectionItemInfo(null);
+    }
+
+    @Test
+    public void testGetSetHintText() {
+        final CharSequence hintText = (Build.VERSION.SDK_INT >= 19) ? "hint text" : null;
+        AccessibilityNodeInfoCompat nodeCompat = obtainedWrappedNodeCompat();
+        nodeCompat.setHintText(hintText);
+        assertThat(nodeCompat.getHintText(), equalTo(hintText));
+    }
+
+    @Test
+    public void testGetSetPaneTitle() {
+        final CharSequence paneTitle = (Build.VERSION.SDK_INT >= 19) ? "pane title" : null;
+        AccessibilityNodeInfoCompat nodeCompat = obtainedWrappedNodeCompat();
+        nodeCompat.setPaneTitle(paneTitle);
+        assertThat(nodeCompat.getPaneTitle(), equalTo(paneTitle));
+    }
+
+    @Test
+    public void testGetSetTooltipText() {
+        final CharSequence tooltipText = (Build.VERSION.SDK_INT >= 19) ? "tooltip" : null;
+        AccessibilityNodeInfoCompat nodeCompat = obtainedWrappedNodeCompat();
+        nodeCompat.setTooltipText(tooltipText);
+        assertThat(nodeCompat.getTooltipText(), equalTo(tooltipText));
+    }
+
+    @Test
+    public void testGetSetShowingHintText() {
+        assumeTrue(Build.VERSION.SDK_INT >= 19);
+        AccessibilityNodeInfoCompat nodeCompat = obtainedWrappedNodeCompat();
+        nodeCompat.setShowingHintText(true);
+        assertThat(nodeCompat.isShowingHintText(), is(true));
+        nodeCompat.setShowingHintText(false);
+        assertThat(nodeCompat.isShowingHintText(), is(false));
+    }
+
+    @Test
+    public void testGetSetScreenReaderFocusable() {
+        assumeTrue(Build.VERSION.SDK_INT >= 19);
+        AccessibilityNodeInfoCompat nodeCompat = obtainedWrappedNodeCompat();
+        nodeCompat.setScreenReaderFocusable(true);
+        assertThat(nodeCompat.isScreenReaderFocusable(), is(true));
+        nodeCompat.setScreenReaderFocusable(false);
+        assertThat(nodeCompat.isScreenReaderFocusable(), is(false));
+    }
+
+    @Test
+    public void testGetSetHeading() {
+        assumeTrue(Build.VERSION.SDK_INT >= 19);
+        AccessibilityNodeInfoCompat nodeCompat = obtainedWrappedNodeCompat();
+        nodeCompat.setHeading(true);
+        assertThat(nodeCompat.isHeading(), is(true));
+        nodeCompat.setHeading(false);
+        assertThat(nodeCompat.isHeading(), is(false));
+    }
+
+    private AccessibilityNodeInfoCompat obtainedWrappedNodeCompat() {
+        AccessibilityNodeInfo accessibilityNodeInfo = AccessibilityNodeInfo.obtain();
+        return AccessibilityNodeInfoCompat.wrap(accessibilityNodeInfo);
+    }
+}
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/tests/res/font/sample_font_collection.ttc b/compat/src/androidTest/res/font/sample_font_collection.ttc
similarity index 100%
rename from compat/tests/res/font/sample_font_collection.ttc
rename to 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/tests/res/font/samplexmlfontforparsing.xml b/compat/src/androidTest/res/font/samplexmlfontforparsing.xml
similarity index 100%
rename from compat/tests/res/font/samplexmlfontforparsing.xml
rename to compat/src/androidTest/res/font/samplexmlfontforparsing.xml
diff --git a/compat/tests/res/font/samplexmlfontforparsing2.xml b/compat/src/androidTest/res/font/samplexmlfontforparsing2.xml
similarity index 100%
rename from compat/tests/res/font/samplexmlfontforparsing2.xml
rename to compat/src/androidTest/res/font/samplexmlfontforparsing2.xml
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/tests/res/font/ttctestfont1.xml b/compat/src/androidTest/res/font/ttctestfont1.xml
similarity index 100%
rename from compat/tests/res/font/ttctestfont1.xml
rename to compat/src/androidTest/res/font/ttctestfont1.xml
diff --git a/compat/tests/res/font/ttctestfont2.xml b/compat/src/androidTest/res/font/ttctestfont2.xml
similarity index 100%
rename from compat/tests/res/font/ttctestfont2.xml
rename to compat/src/androidTest/res/font/ttctestfont2.xml
diff --git a/compat/tests/res/font/variable_width_dash_font.ttf b/compat/src/androidTest/res/font/variable_width_dash_font.ttf
similarity index 100%
rename from compat/tests/res/font/variable_width_dash_font.ttf
rename to compat/src/androidTest/res/font/variable_width_dash_font.ttf
Binary files differ
diff --git a/compat/tests/res/font/variationsettingstestfont1.xml b/compat/src/androidTest/res/font/variationsettingstestfont1.xml
similarity index 100%
rename from compat/tests/res/font/variationsettingstestfont1.xml
rename to compat/src/androidTest/res/font/variationsettingstestfont1.xml
diff --git a/compat/tests/res/font/variationsettingstestfont2.xml b/compat/src/androidTest/res/font/variationsettingstestfont2.xml
similarity index 100%
rename from compat/tests/res/font/variationsettingstestfont2.xml
rename to compat/src/androidTest/res/font/variationsettingstestfont2.xml
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/AndroidManifest.xml b/compat/src/main/AndroidManifest.xml
similarity index 100%
rename from compat/AndroidManifest.xml
rename to compat/src/main/AndroidManifest.xml
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 1e2f317..5cb2ec9 100644
--- a/compat/src/main/java/android/support/v4/app/NotificationCompat.java
+++ b/compat/src/main/java/android/support/v4/app/NotificationCompat.java
@@ -17,6 +17,7 @@
 package android.support.v4.app;
 
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
 import android.app.Activity;
@@ -2884,6 +2885,11 @@
          */
         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";
 
@@ -3319,6 +3325,7 @@
              * @param label the label to display while the action is being prepared to execute
              * @return this object for method chaining
              */
+            @Deprecated
             public WearableExtender setInProgressLabel(CharSequence label) {
                 mInProgressLabel = label;
                 return this;
@@ -3330,6 +3337,7 @@
              *
              * @return the label to display while the action is being prepared to execute
              */
+            @Deprecated
             public CharSequence getInProgressLabel() {
                 return mInProgressLabel;
             }
@@ -3341,6 +3349,7 @@
              * @param label the label to confirm the action should be executed
              * @return this object for method chaining
              */
+            @Deprecated
             public WearableExtender setConfirmLabel(CharSequence label) {
                 mConfirmLabel = label;
                 return this;
@@ -3352,6 +3361,7 @@
              *
              * @return the label to confirm the action should be executed
              */
+            @Deprecated
             public CharSequence getConfirmLabel() {
                 return mConfirmLabel;
             }
@@ -3363,6 +3373,7 @@
              * @param label the label to display to cancel the action
              * @return this object for method chaining
              */
+            @Deprecated
             public WearableExtender setCancelLabel(CharSequence label) {
                 mCancelLabel = label;
                 return this;
@@ -3374,6 +3385,7 @@
              *
              * @return the label to display to cancel the action
              */
+            @Deprecated
             public CharSequence getCancelLabel() {
                 return mCancelLabel;
             }
@@ -3446,7 +3458,8 @@
                 SEMANTIC_ACTION_MUTE,
                 SEMANTIC_ACTION_UNMUTE,
                 SEMANTIC_ACTION_THUMBS_UP,
-                SEMANTIC_ACTION_THUMBS_DOWN
+                SEMANTIC_ACTION_THUMBS_DOWN,
+                SEMANTIC_ACTION_CALL
         })
         @Retention(RetentionPolicy.SOURCE)
         public @interface SemanticAction {}
@@ -3967,6 +3980,7 @@
         /**
          * Set an icon that goes with the content of this notification.
          */
+        @Deprecated
         public WearableExtender setContentIcon(int icon) {
             mContentIcon = icon;
             return this;
@@ -3975,6 +3989,7 @@
         /**
          * Get an icon that goes with the content of this notification.
          */
+        @Deprecated
         public int getContentIcon() {
             return mContentIcon;
         }
@@ -3985,6 +4000,7 @@
          * {@link android.view.Gravity#END}. The default value is {@link android.view.Gravity#END}.
          * @see #setContentIcon
          */
+        @Deprecated
         public WearableExtender setContentIconGravity(int contentIconGravity) {
             mContentIconGravity = contentIconGravity;
             return this;
@@ -3996,6 +4012,7 @@
          * {@link android.view.Gravity#END}. The default value is {@link android.view.Gravity#END}.
          * @see #getContentIcon
          */
+        @Deprecated
         public int getContentIconGravity() {
             return mContentIconGravity;
         }
@@ -4043,6 +4060,7 @@
          * {@link android.view.Gravity#CENTER_VERTICAL} and {@link android.view.Gravity#BOTTOM}.
          * The default value is {@link android.view.Gravity#BOTTOM}.
          */
+        @Deprecated
         public WearableExtender setGravity(int gravity) {
             mGravity = gravity;
             return this;
@@ -4054,6 +4072,7 @@
          * {@link android.view.Gravity#CENTER_VERTICAL} and {@link android.view.Gravity#BOTTOM}.
          * The default value is {@link android.view.Gravity#BOTTOM}.
          */
+        @Deprecated
         public int getGravity() {
             return mGravity;
         }
@@ -4067,6 +4086,7 @@
          * documentation for the preset in question. See also
          * {@link #setCustomContentHeight} and {@link #getCustomSizePreset}.
          */
+        @Deprecated
         public WearableExtender setCustomSizePreset(int sizePreset) {
             mCustomSizePreset = sizePreset;
             return this;
@@ -4080,6 +4100,7 @@
          * using {@link #setDisplayIntent}. Check the documentation for the preset in question.
          * See also {@link #setCustomContentHeight} and {@link #setCustomSizePreset}.
          */
+        @Deprecated
         public int getCustomSizePreset() {
             return mCustomSizePreset;
         }
@@ -4091,6 +4112,7 @@
          * {@link NotificationCompat.WearableExtender#setCustomSizePreset} and
          * {@link #getCustomContentHeight}.
          */
+        @Deprecated
         public WearableExtender setCustomContentHeight(int height) {
             mCustomContentHeight = height;
             return this;
@@ -4102,6 +4124,7 @@
          * using {@link #setDisplayIntent}. See also {@link #setCustomSizePreset} and
          * {@link #setCustomContentHeight}.
          */
+        @Deprecated
         public int getCustomContentHeight() {
             return mCustomContentHeight;
         }
@@ -4152,6 +4175,7 @@
          * @param hintHideIcon {@code true} to hide the icon, {@code false} otherwise.
          * @return this object for method chaining
          */
+        @Deprecated
         public WearableExtender setHintHideIcon(boolean hintHideIcon) {
             setFlag(FLAG_HINT_HIDE_ICON, hintHideIcon);
             return this;
@@ -4162,6 +4186,7 @@
          * @return {@code true} if this icon should not be displayed, false otherwise.
          * The default value is {@code false} if this was never set.
          */
+        @Deprecated
         public boolean getHintHideIcon() {
             return (mFlags & FLAG_HINT_HIDE_ICON) != 0;
         }
@@ -4171,6 +4196,7 @@
          * displayed, and other semantic content should be hidden. This hint is only applicable
          * to sub-pages added using {@link #addPage}.
          */
+        @Deprecated
         public WearableExtender setHintShowBackgroundOnly(boolean hintShowBackgroundOnly) {
             setFlag(FLAG_HINT_SHOW_BACKGROUND_ONLY, hintShowBackgroundOnly);
             return this;
@@ -4181,6 +4207,7 @@
          * displayed, and other semantic content should be hidden. This hint is only applicable
          * to sub-pages added using {@link NotificationCompat.WearableExtender#addPage}.
          */
+        @Deprecated
         public boolean getHintShowBackgroundOnly() {
             return (mFlags & FLAG_HINT_SHOW_BACKGROUND_ONLY) != 0;
         }
@@ -4192,6 +4219,7 @@
          * @param hintAvoidBackgroundClipping {@code true} to avoid clipping if possible.
          * @return this object for method chaining
          */
+        @Deprecated
         public WearableExtender setHintAvoidBackgroundClipping(
                 boolean hintAvoidBackgroundClipping) {
             setFlag(FLAG_HINT_AVOID_BACKGROUND_CLIPPING, hintAvoidBackgroundClipping);
@@ -4205,6 +4233,7 @@
          * @return {@code true} if it's ok if the background is clipped on the screen, false
          * otherwise. The default value is {@code false} if this was never set.
          */
+        @Deprecated
         public boolean getHintAvoidBackgroundClipping() {
             return (mFlags & FLAG_HINT_AVOID_BACKGROUND_CLIPPING) != 0;
         }
@@ -4216,6 +4245,7 @@
          *     {@link #SCREEN_TIMEOUT_SHORT} or {@link #SCREEN_TIMEOUT_LONG}.
          * @return this object for method chaining
          */
+        @Deprecated
         public WearableExtender setHintScreenTimeout(int timeout) {
             mHintScreenTimeout = timeout;
             return this;
@@ -4227,6 +4257,7 @@
          * @return the duration in milliseconds if > 0, or either one of the sentinel values
          *     {@link #SCREEN_TIMEOUT_SHORT} or {@link #SCREEN_TIMEOUT_LONG}.
          */
+        @Deprecated
         public int getHintScreenTimeout() {
             return mHintScreenTimeout;
         }
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/compat/src/main/java/android/support/v4/content/ContextCompat.java b/compat/src/main/java/android/support/v4/content/ContextCompat.java
index 58cdfb4..6aba339 100644
--- a/compat/src/main/java/android/support/v4/content/ContextCompat.java
+++ b/compat/src/main/java/android/support/v4/content/ContextCompat.java
@@ -20,7 +20,6 @@
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.res.ColorStateList;
-import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
 import android.os.Build;
 import android.os.Bundle;
@@ -353,14 +352,12 @@
      *           The value 0 is an invalid identifier.
      * @return Drawable An object that can be used to draw this resource.
      */
-    @NonNull
+    @Nullable
     public static Drawable getDrawable(@NonNull Context context, @DrawableRes int id) {
-        @Nullable
-        final Drawable drawable;
         if (Build.VERSION.SDK_INT >= 21) {
-            drawable = context.getDrawable(id);
+            return context.getDrawable(id);
         } else if (Build.VERSION.SDK_INT >= 16) {
-            drawable = context.getResources().getDrawable(id);
+            return context.getResources().getDrawable(id);
         } else {
             // Prior to JELLY_BEAN, Resources.getDrawable() would not correctly
             // retrieve the final configuration density when the resource ID
@@ -374,16 +371,8 @@
                 context.getResources().getValue(id, sTempValue, true);
                 resolvedId = sTempValue.resourceId;
             }
-            drawable = context.getResources().getDrawable(resolvedId);
+            return context.getResources().getDrawable(resolvedId);
         }
-
-        // verify the drawable is non-null. Prior to a platform change, null could be returned only
-        // by BitmapFactory decoding failure, so this check safely enables @NonNull access by
-        // throwing in those cases
-        if (drawable == null) {
-            throw new Resources.NotFoundException("could not decode drawable from resource stream");
-        }
-        return drawable;
     }
 
     /**
@@ -395,18 +384,17 @@
      * @param id The desired resource identifier, as generated by the aapt
      *           tool. This integer encodes the package, type, and resource
      *           entry. The value 0 is an invalid identifier.
-     * @return A color state list.
+     * @return A color state list, or {@code null} if the resource could not be
+     *         resolved.
      * @throws android.content.res.Resources.NotFoundException if the given ID
      *         does not exist.
      */
-    @NonNull
+    @Nullable
     public static ColorStateList getColorStateList(@NonNull Context context,
             @ColorRes int id) {
         if (Build.VERSION.SDK_INT >= 23) {
-            //noinspection ConstantConditions - Platform @Nullable annotation currently incorrect
             return context.getColorStateList(id);
         } else {
-            //noinspection ConstantConditions - Platform @Nullable annotation currently incorrect
             return context.getResources().getColorStateList(id);
         }
     }
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/res/ResourcesCompat.java b/compat/src/main/java/android/support/v4/content/res/ResourcesCompat.java
index 671606e..15b8ce9 100644
--- a/compat/src/main/java/android/support/v4/content/res/ResourcesCompat.java
+++ b/compat/src/main/java/android/support/v4/content/res/ResourcesCompat.java
@@ -72,25 +72,15 @@
      * @throws NotFoundException Throws NotFoundException if the given ID does
      *         not exist.
      */
-    @NonNull
+    @Nullable
     @SuppressWarnings("deprecation")
     public static Drawable getDrawable(@NonNull Resources res, @DrawableRes int id,
             @Nullable Theme theme) throws NotFoundException {
-        @Nullable
-        final Drawable drawable;
         if (SDK_INT >= 21) {
-            drawable = res.getDrawable(id, theme);
+            return res.getDrawable(id, theme);
         } else {
-            drawable = res.getDrawable(id);
+            return res.getDrawable(id);
         }
-
-        // verify the drawable is non-null. Prior to a platform change, null could be returned only
-        // by BitmapFactory decoding failure, so this check safely enables @NonNull access by
-        // throwing in those cases
-        if (drawable == null) {
-            throw new NotFoundException("could not decode drawable from resource stream");
-        }
-        return drawable;
     }
 
 
@@ -115,27 +105,17 @@
      * @throws NotFoundException Throws NotFoundException if the given ID does
      *         not exist.
      */
-    @NonNull
+    @Nullable
     @SuppressWarnings("deprecation")
     public static Drawable getDrawableForDensity(@NonNull Resources res, @DrawableRes int id,
             int density, @Nullable Theme theme) throws NotFoundException {
-        @Nullable
-        final Drawable drawable;
         if (SDK_INT >= 21) {
-            drawable = res.getDrawableForDensity(id, density, theme);
+            return res.getDrawableForDensity(id, density, theme);
         } else if (SDK_INT >= 15) {
-            drawable = res.getDrawableForDensity(id, density);
+            return res.getDrawableForDensity(id, density);
         } else {
-            drawable = res.getDrawable(id);
+            return res.getDrawable(id);
         }
-
-        // verify the drawable is non-null. Prior to a platform change, null could be returned only
-        // by BitmapFactory decoding failure, so this check safely enables @NonNull access by
-        // throwing in those cases
-        if (drawable == null) {
-            throw new NotFoundException("could not decode drawable from resource stream");
-        }
-        return drawable;
     }
 
     /**
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/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/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 febb5d5..0000000
--- a/compat/src/main/java/android/support/v4/util/LongSparseArray.java
+++ /dev/null
@@ -1,399 +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;
-    }
-
-    /**
-     * 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/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 5238cf0..0000000
--- a/compat/src/main/java/android/support/v4/util/SparseArrayCompat.java
+++ /dev/null
@@ -1,394 +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;
-    }
-
-    /**
-     * 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/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/accessibility/AccessibilityNodeInfoCompat.java b/compat/src/main/java/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.java
index d76481c..17e591e 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
@@ -25,6 +25,7 @@
 import android.support.annotation.Nullable;
 import android.support.annotation.RestrictTo;
 import android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat;
+import android.support.v4.os.BuildCompat;
 import android.support.v4.view.ViewCompat;
 import android.text.InputType;
 import android.view.View;
@@ -38,6 +39,7 @@
  * Helper for accessing {@link android.view.accessibility.AccessibilityNodeInfo} in a backwards
  * compatible fashion.
  */
+@SuppressWarnings("NewApi")
 public class AccessibilityNodeInfoCompat {
 
     public static class AccessibilityActionCompat {
@@ -415,6 +417,32 @@
                 new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 24
                         ? AccessibilityNodeInfo.AccessibilityAction.ACTION_SET_PROGRESS : null);
 
+        /**
+         * Action to move a window to a new location.
+         * <p>
+         * <strong>Arguments:</strong>
+         * {@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_MOVE_WINDOW_X}
+         * {@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_MOVE_WINDOW_Y}
+         */
+        public static final AccessibilityActionCompat ACTION_MOVE_WINDOW =
+                new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 26
+                        ? AccessibilityNodeInfo.AccessibilityAction.ACTION_MOVE_WINDOW : null);
+
+        /**
+         * Action to show a tooltip.
+         */
+        public static final AccessibilityActionCompat ACTION_SHOW_TOOLTIP =
+                new AccessibilityActionCompat(BuildCompat.isAtLeastP()
+                        ? AccessibilityNodeInfo.AccessibilityAction.ACTION_SHOW_TOOLTIP : null);
+
+        /**
+         * Action to hide a tooltip. A node should expose this action only for views that are
+         * currently showing a tooltip.
+         */
+        public static final AccessibilityActionCompat ACTION_HIDE_TOOLTIP =
+                new AccessibilityActionCompat(BuildCompat.isAtLeastP()
+                        ? AccessibilityNodeInfo.AccessibilityAction.ACTION_HIDE_TOOLTIP : null);
+
         final Object mAction;
 
         /**
@@ -829,6 +857,24 @@
     private static final String ROLE_DESCRIPTION_KEY =
             "AccessibilityNodeInfo.roleDescription";
 
+    private static final String PANE_TITLE_KEY =
+            "androidx.view.accessibility.AccessibilityNodeInfoCompat.PANE_TITLE_KEY";
+
+    private static final String TOOLTIP_TEXT_KEY =
+            "androidx.view.accessibility.AccessibilityNodeInfoCompat.TOOLTIP_TEXT_KEY";
+
+    private static final String HINT_TEXT_KEY =
+            "androidx.view.accessibility.AccessibilityNodeInfoCompat.HINT_TEXT_KEY";
+
+    private static final String BOOLEAN_PROPERTY_KEY =
+            "androidx.view.accessibility.AccessibilityNodeInfoCompat.BOOLEAN_PROPERTY_KEY";
+
+    // These don't line up with the internal framework constants, since they are independent
+    // and we might as well get all 32 bits of utility here.
+    private static final int BOOLEAN_PROPERTY_SCREEN_READER_FOCUSABLE = 0x00000001;
+    private static final int BOOLEAN_PROPERTY_IS_HEADING = 0x00000002;
+    private static final int BOOLEAN_PROPERTY_IS_SHOWING_HINT = 0x00000004;
+
     private final AccessibilityNodeInfo mInfo;
 
     /**
@@ -1173,6 +1219,34 @@
     public static final String ACTION_ARGUMENT_PROGRESS_VALUE =
             "android.view.accessibility.action.ARGUMENT_PROGRESS_VALUE";
 
+    /**
+     * Argument for specifying the x coordinate to which to move a window.
+     * <p>
+     * <strong>Type:</strong> int<br>
+     * <strong>Actions:</strong>
+     * <ul>
+     *     <li>{@link AccessibilityActionCompat#ACTION_MOVE_WINDOW}</li>
+     * </ul>
+     *
+     * @see AccessibilityActionCompat#ACTION_MOVE_WINDOW
+     */
+    public static final String ACTION_ARGUMENT_MOVE_WINDOW_X =
+            "ACTION_ARGUMENT_MOVE_WINDOW_X";
+
+    /**
+     * Argument for specifying the y coordinate to which to move a window.
+     * <p>
+     * <strong>Type:</strong> int<br>
+     * <strong>Actions:</strong>
+     * <ul>
+     *     <li>{@link AccessibilityActionCompat#ACTION_MOVE_WINDOW}</li>
+     * </ul>
+     *
+     * @see AccessibilityActionCompat#ACTION_MOVE_WINDOW
+     */
+    public static final String ACTION_ARGUMENT_MOVE_WINDOW_Y =
+            "ACTION_ARGUMENT_MOVE_WINDOW_Y";
+
     // Focus types
 
     /**
@@ -2491,6 +2565,42 @@
     }
 
     /**
+     * Gets the hint text of this node. Only applies to nodes where text can be entered.
+     *
+     * @return The hint text.
+     */
+    public @Nullable CharSequence getHintText() {
+        if (Build.VERSION.SDK_INT >= 26) {
+            return mInfo.getHintText();
+        } else if (Build.VERSION.SDK_INT >= 19) {
+            return mInfo.getExtras().getCharSequence(HINT_TEXT_KEY);
+        }
+        return null;
+    }
+
+    /**
+     * Sets the hint text of this node. Only applies to nodes where text can be entered.
+     * <p>This method has no effect below API 19</p>
+     * <p>
+     *   <strong>Note:</strong> Cannot be called from an
+     *   {@link android.accessibilityservice.AccessibilityService}.
+     *   This class is made immutable before being delivered to an AccessibilityService.
+     * </p>
+     *
+     * @param hintText The hint text for this mode.
+     *
+     * @throws IllegalStateException If called from an AccessibilityService.
+     */
+    public void setHintText(@Nullable CharSequence hintText) {
+        if (Build.VERSION.SDK_INT >= 26) {
+            mInfo.setHintText(hintText);
+        } else if (Build.VERSION.SDK_INT >= 19) {
+            mInfo.getExtras().putCharSequence(HINT_TEXT_KEY, hintText);
+        }
+    }
+
+
+    /**
      * Sets the error text of this node.
      * <p>
      *   <strong>Note:</strong> Cannot be called from an
@@ -3058,6 +3168,173 @@
     }
 
     /**
+     * Gets the tooltip text of this node.
+     *
+     * @return The tooltip text.
+     */
+    @Nullable
+    public CharSequence getTooltipText() {
+        if (BuildCompat.isAtLeastP()) {
+            return mInfo.getTooltipText();
+        } else if (Build.VERSION.SDK_INT >= 19) {
+            return mInfo.getExtras().getCharSequence(TOOLTIP_TEXT_KEY);
+        }
+        return null;
+    }
+
+    /**
+     * Sets the tooltip text of this node.
+     * <p>This method has no effect below API 19</p>
+     * <p>
+     *   <strong>Note:</strong> Cannot be called from an
+     *   {@link android.accessibilityservice.AccessibilityService}.
+     *   This class is made immutable before being delivered to an AccessibilityService.
+     * </p>
+     *
+     * @param tooltipText The tooltip text.
+     *
+     * @throws IllegalStateException If called from an AccessibilityService.
+     */
+    public void setTooltipText(@Nullable CharSequence tooltipText) {
+        if (BuildCompat.isAtLeastP()) {
+            mInfo.setTooltipText(tooltipText);
+        } else if (Build.VERSION.SDK_INT >= 19) {
+            mInfo.getExtras().putCharSequence(TOOLTIP_TEXT_KEY, tooltipText);
+        }
+    }
+
+    /**
+     * If this node represents a visually distinct region of the screen that may update separately
+     * from the rest of the window, it is considered a pane. Set the pane title to indicate that
+     * the node is a pane, and to provide a title for it.
+     * <p>This method has no effect below API 19</p>
+     * <p>
+     *   <strong>Note:</strong> Cannot be called from an
+     *   {@link android.accessibilityservice.AccessibilityService}.
+     *   This class is made immutable before being delivered to an AccessibilityService.
+     * </p>
+     * @param paneTitle The title of the window represented by this node.
+     */
+    public void setPaneTitle(@Nullable CharSequence paneTitle) {
+        if (BuildCompat.isAtLeastP()) {
+            mInfo.setPaneTitle(paneTitle);
+        } else if (Build.VERSION.SDK_INT >= 19) {
+            mInfo.getExtras().putCharSequence(PANE_TITLE_KEY, paneTitle);
+        }
+    }
+
+    /**
+     * Get the title of the pane represented by this node.
+     *
+     * @return The title of the pane represented by this node, or {@code null} if this node does
+     *         not represent a pane.
+     */
+    public @Nullable CharSequence getPaneTitle() {
+        if (BuildCompat.isAtLeastP()) {
+            return mInfo.getPaneTitle();
+        } else if (Build.VERSION.SDK_INT >= 19) {
+            return mInfo.getExtras().getCharSequence(PANE_TITLE_KEY);
+        }
+        return null;
+    }
+
+    /**
+     * Returns whether the node is explicitly marked as a focusable unit by a screen reader. Note
+     * that {@code false} indicates that it is not explicitly marked, not that the node is not
+     * a focusable unit. Screen readers should generally use other signals, such as
+     * {@link #isFocusable()}, or the presence of text in a node, to determine what should receive
+     * focus.
+     *
+     * @return {@code true} if the node is specifically marked as a focusable unit for screen
+     *         readers, {@code false} otherwise.
+     */
+    public boolean isScreenReaderFocusable() {
+        if (BuildCompat.isAtLeastP()) {
+            return mInfo.isScreenReaderFocusable();
+        }
+        return getBooleanProperty(BOOLEAN_PROPERTY_SCREEN_READER_FOCUSABLE);
+    }
+
+    /**
+     * Sets whether the node should be considered a focusable unit by a screen reader.
+     * <p>This method has no effect below API 19</p>
+     * <p>
+     *   <strong>Note:</strong> Cannot be called from an
+     *   {@link android.accessibilityservice.AccessibilityService}.
+     *   This class is made immutable before being delivered to an AccessibilityService.
+     * </p>
+     *
+     * @param screenReaderFocusable {@code true} if the node is a focusable unit for screen readers,
+     *                              {@code false} otherwise.
+     */
+    public void setScreenReaderFocusable(boolean screenReaderFocusable) {
+        if (BuildCompat.isAtLeastP()) {
+            mInfo.setScreenReaderFocusable(screenReaderFocusable);
+        } else {
+            setBooleanProperty(BOOLEAN_PROPERTY_SCREEN_READER_FOCUSABLE, screenReaderFocusable);
+        }
+    }
+
+    /**
+     * Returns whether the node's text represents a hint for the user to enter text. It should only
+     * be {@code true} if the node has editable text.
+     *
+     * @return {@code true} if the text in the node represents a hint to the user, {@code false}
+     * otherwise.
+     */
+    public boolean isShowingHintText() {
+        if (Build.VERSION.SDK_INT >= 26) {
+            return mInfo.isShowingHintText();
+        }
+        return getBooleanProperty(BOOLEAN_PROPERTY_IS_SHOWING_HINT);
+    }
+
+    /**
+     * Sets whether the node's text represents a hint for the user to enter text. It should only
+     * be {@code true} if the node has editable text.
+     * <p>This method has no effect below API 19</p>
+     * <p>
+     *   <strong>Note:</strong> Cannot be called from an
+     *   {@link android.accessibilityservice.AccessibilityService}.
+     *   This class is made immutable before being delivered to an AccessibilityService.
+     * </p>
+     *
+     * @param showingHintText {@code true} if the text in the node represents a hint to the user,
+     * {@code false} otherwise.
+     */
+    public void setShowingHintText(boolean showingHintText) {
+        if (Build.VERSION.SDK_INT >= 26) {
+            mInfo.setShowingHintText(showingHintText);
+        } else {
+            setBooleanProperty(BOOLEAN_PROPERTY_IS_SHOWING_HINT, showingHintText);
+        }
+    }
+
+    /**
+     * Returns whether node represents a heading.
+     *
+     * @return {@code true} if the node is a heading, {@code false} otherwise.
+     */
+    public boolean isHeading() {
+        return getBooleanProperty(BOOLEAN_PROPERTY_IS_HEADING);
+    }
+
+    /**
+     * Sets whether the node represents a heading.
+     * <p>This method has no effect below API 19</p>
+     * <p>
+     *   <strong>Note:</strong> Cannot be called from an
+     *   {@link android.accessibilityservice.AccessibilityService}.
+     *   This class is made immutable before being delivered to an AccessibilityService.
+     * </p>
+     *
+     * @param isHeading {@code true} if the node is a heading, {@code false} otherwise.
+     */
+    public void setHeading(boolean isHeading) {
+        setBooleanProperty(BOOLEAN_PROPERTY_IS_HEADING, isHeading);
+    }
+
+    /**
      * Refreshes this info with the latest state of the view it represents.
      * <p>
      * <strong>Note:</strong> If this method returns false this info is obsolete
@@ -3187,6 +3464,22 @@
         return builder.toString();
     }
 
+    private void setBooleanProperty(int property, boolean value) {
+        Bundle extras = getExtras();
+        if (extras != null) {
+            int booleanProperties = extras.getInt(BOOLEAN_PROPERTY_KEY, 0);
+            booleanProperties &= ~property;
+            booleanProperties |= (value) ? property : 0;
+            extras.putInt(BOOLEAN_PROPERTY_KEY, booleanProperties);
+        }
+    }
+
+    private boolean getBooleanProperty(int property) {
+        Bundle extras = getExtras();
+        if (extras == null) return false;
+        return (extras.getInt(BOOLEAN_PROPERTY_KEY, 0) & property) == property;
+    }
+
     private static String getActionSymbolicName(int action) {
         switch (action) {
             case ACTION_FOCUS:
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/content/ContextCompatTest.java b/compat/tests/java/android/support/v4/content/ContextCompatTest.java
deleted file mode 100644
index 3ada86c..0000000
--- a/compat/tests/java/android/support/v4/content/ContextCompatTest.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.v4.content;
-
-import static org.junit.Assert.assertEquals;
-
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.content.res.ColorStateList;
-import android.content.res.Resources;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-import android.support.compat.test.R;
-import android.support.test.filters.SmallTest;
-import android.support.v4.BaseInstrumentationTestCase;
-import android.support.v4.ThemedYellowActivity;
-import android.support.v4.testutils.TestUtils;
-import android.util.DisplayMetrics;
-
-import org.junit.Before;
-import org.junit.Test;
-
-@SmallTest
-public class ContextCompatTest extends BaseInstrumentationTestCase<ThemedYellowActivity> {
-    private Context mContext;
-
-    public ContextCompatTest() {
-        super(ThemedYellowActivity.class);
-    }
-
-    @Before
-    public void setup() {
-        mContext = mActivityTestRule.getActivity();
-    }
-
-    @Test
-    public void testGetColor() throws Throwable {
-        assertEquals("Unthemed color load", 0xFFFF8090,
-                ContextCompat.getColor(mContext, R.color.text_color));
-
-        if (Build.VERSION.SDK_INT >= 23) {
-            // The following test is only expected to pass on v23+ devices. The result of
-            // calling theme-aware getColor() in pre-v23 is undefined.
-            assertEquals("Themed yellow color load",
-                    ContextCompat.getColor(mContext, R.color.simple_themed_selector),
-                    0xFFF0B000);
-        }
-    }
-
-    @Test
-    public void testGetColorStateList() throws Throwable {
-        ColorStateList unthemedColorStateList =
-                ContextCompat.getColorStateList(mContext, R.color.complex_unthemed_selector);
-        assertEquals("Unthemed color state list load: default", 0xFF70A0C0,
-                unthemedColorStateList.getDefaultColor());
-        assertEquals("Unthemed color state list load: focused", 0xFF70B0F0,
-                unthemedColorStateList.getColorForState(
-                        new int[]{android.R.attr.state_focused}, 0));
-        assertEquals("Unthemed color state list load: pressed", 0xFF6080B0,
-                unthemedColorStateList.getColorForState(
-                        new int[]{android.R.attr.state_pressed}, 0));
-
-        if (Build.VERSION.SDK_INT >= 23) {
-            // The following tests are only expected to pass on v23+ devices. The result of
-            // calling theme-aware getColorStateList() in pre-v23 is undefined.
-            ColorStateList themedYellowColorStateList =
-                    ContextCompat.getColorStateList(mContext, R.color.complex_themed_selector);
-            assertEquals("Themed yellow color state list load: default", 0xFFF0B000,
-                    themedYellowColorStateList.getDefaultColor());
-            assertEquals("Themed yellow color state list load: focused", 0xFFF0A020,
-                    themedYellowColorStateList.getColorForState(
-                            new int[]{android.R.attr.state_focused}, 0));
-            assertEquals("Themed yellow color state list load: pressed", 0xFFE0A040,
-                    themedYellowColorStateList.getColorForState(
-                            new int[]{android.R.attr.state_pressed}, 0));
-        }
-    }
-
-    @Test
-    public void testGetDrawable() throws Throwable {
-        Drawable unthemedDrawable =
-                ContextCompat.getDrawable(mContext, R.drawable.test_drawable_red);
-        TestUtils.assertAllPixelsOfColor("Unthemed drawable load",
-                unthemedDrawable, mContext.getResources().getColor(R.color.test_red));
-
-        if (Build.VERSION.SDK_INT >= 23) {
-            // The following test is only expected to pass on v23+ devices. The result of
-            // calling theme-aware getDrawable() in pre-v23 is undefined.
-            Drawable themedYellowDrawable =
-                    ContextCompat.getDrawable(mContext, R.drawable.themed_drawable);
-            TestUtils.assertAllPixelsOfColor("Themed yellow drawable load",
-                    themedYellowDrawable, 0xFFF0B000);
-        }
-    }
-
-    @Test(expected = Resources.NotFoundException.class)
-    public void testGetDrawableCannotDecode() {
-        ContextCompat.getDrawable(mContext, R.drawable.fake_image_will_not_decode);
-    }
-
-    @Test
-    public void testDrawableConfigurationWorkaround() throws Throwable {
-        final int expectedWidth = scaleFromDensity(7, DisplayMetrics.DENSITY_LOW,
-                mContext.getResources().getDisplayMetrics().densityDpi);
-
-        // Ensure we retrieve the correct drawable configuration. Specifically,
-        // this tests a workaround for a bug in drawable configuration that
-        // exists on API < 16 for references to drawables.
-        Drawable referencedDrawable = ContextCompat.getDrawable(mContext,
-                R.drawable.aliased_drawable);
-        assertEquals("Drawable configuration does not match DisplayMetrics",
-                expectedWidth, referencedDrawable.getIntrinsicWidth());
-    }
-
-    private static int scaleFromDensity(int size, int sdensity, int tdensity) {
-        if (sdensity == tdensity) {
-            return size;
-        }
-
-        // Scale by tdensity / sdensity, rounding up.
-        return ((size * tdensity) + (sdensity >> 1)) / sdensity;
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testCheckSelfPermissionNull() {
-        ContextCompat.checkSelfPermission(mContext, null);
-    }
-
-    @Test
-    public void testCheckSelfPermission() {
-        assertEquals("Vibrate permission granted", PackageManager.PERMISSION_GRANTED,
-                ContextCompat.checkSelfPermission(mContext,
-                        android.Manifest.permission.VIBRATE));
-        assertEquals("Wake lock permission granted", PackageManager.PERMISSION_GRANTED,
-                ContextCompat.checkSelfPermission(mContext,
-                        android.Manifest.permission.WAKE_LOCK));
-
-        // The following permissions (normal and dangerous) are expected to be denied as they are
-        // not declared in our manifest.
-        assertEquals("Access network state permission denied", PackageManager.PERMISSION_DENIED,
-                ContextCompat.checkSelfPermission(mContext,
-                        android.Manifest.permission.ACCESS_NETWORK_STATE));
-        assertEquals("Bluetooth permission denied", PackageManager.PERMISSION_DENIED,
-                ContextCompat.checkSelfPermission(mContext,
-                        android.Manifest.permission.BLUETOOTH));
-        assertEquals("Call phone permission denied", PackageManager.PERMISSION_DENIED,
-                ContextCompat.checkSelfPermission(mContext,
-                        android.Manifest.permission.CALL_PHONE));
-        assertEquals("Delete packages permission denied", PackageManager.PERMISSION_DENIED,
-                ContextCompat.checkSelfPermission(mContext,
-                        android.Manifest.permission.DELETE_PACKAGES));
-    }
-}
diff --git a/compat/tests/java/android/support/v4/content/res/ResourcesCompatTest.java b/compat/tests/java/android/support/v4/content/res/ResourcesCompatTest.java
deleted file mode 100644
index 8930da6..0000000
--- a/compat/tests/java/android/support/v4/content/res/ResourcesCompatTest.java
+++ /dev/null
@@ -1,436 +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.content.res;
-
-import static org.junit.Assert.assertEquals;
-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 android.content.Context;
-import android.content.res.ColorStateList;
-import android.content.res.Resources;
-import android.graphics.Typeface;
-import android.graphics.drawable.Drawable;
-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.provider.FontsContractCompat;
-import android.support.v4.provider.MockFontProvider;
-import android.support.v4.testutils.TestUtils;
-import android.util.DisplayMetrics;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-@SmallTest
-public class ResourcesCompatTest {
-    private Context mContext;
-    private Resources mResources;
-
-    @Before
-    public void setup() {
-        mContext = InstrumentationRegistry.getContext();
-        mResources = mContext.getResources();
-        MockFontProvider.prepareFontFiles(mContext);
-    }
-
-    @Test
-    public void testGetColor() throws Throwable {
-        assertEquals("Unthemed color load",
-                ResourcesCompat.getColor(mResources, R.color.text_color, null),
-                0xFFFF8090);
-
-        if (Build.VERSION.SDK_INT >= 23) {
-            // The following tests are only expected to pass on v23+ devices. The result of
-            // calling theme-aware getColor() in pre-v23 is undefined.
-            final Resources.Theme yellowTheme = mResources.newTheme();
-            yellowTheme.applyStyle(R.style.YellowTheme, true);
-            assertEquals("Themed yellow color load", 0xFFF0B000,
-                    ResourcesCompat.getColor(mResources, R.color.simple_themed_selector,
-                            yellowTheme));
-
-            final Resources.Theme lilacTheme = mResources.newTheme();
-            lilacTheme.applyStyle(R.style.LilacTheme, true);
-            assertEquals("Themed lilac color load", 0xFFF080F0,
-                    ResourcesCompat.getColor(mResources, R.color.simple_themed_selector,
-                            lilacTheme));
-        }
-    }
-
-    @Test
-    public void testGetColorStateList() throws Throwable {
-        final ColorStateList unthemedColorStateList =
-                ResourcesCompat.getColorStateList(mResources, R.color.complex_unthemed_selector,
-                        null);
-        assertEquals("Unthemed color state list load: default", 0xFF70A0C0,
-                unthemedColorStateList.getDefaultColor());
-        assertEquals("Unthemed color state list load: focused", 0xFF70B0F0,
-                unthemedColorStateList.getColorForState(
-                        new int[]{android.R.attr.state_focused}, 0));
-        assertEquals("Unthemed color state list load: pressed", 0xFF6080B0,
-                unthemedColorStateList.getColorForState(
-                        new int[]{android.R.attr.state_pressed}, 0));
-
-        if (Build.VERSION.SDK_INT >= 23) {
-            // The following tests are only expected to pass on v23+ devices. The result of
-            // calling theme-aware getColorStateList() in pre-v23 is undefined.
-            final Resources.Theme yellowTheme = mResources.newTheme();
-            yellowTheme.applyStyle(R.style.YellowTheme, true);
-            final ColorStateList themedYellowColorStateList =
-                    ResourcesCompat.getColorStateList(mResources, R.color.complex_themed_selector,
-                            yellowTheme);
-            assertEquals("Themed yellow color state list load: default", 0xFFF0B000,
-                    themedYellowColorStateList.getDefaultColor());
-            assertEquals("Themed yellow color state list load: focused", 0xFFF0A020,
-                    themedYellowColorStateList.getColorForState(
-                            new int[]{android.R.attr.state_focused}, 0));
-            assertEquals("Themed yellow color state list load: pressed", 0xFFE0A040,
-                    themedYellowColorStateList.getColorForState(
-                            new int[]{android.R.attr.state_pressed}, 0));
-
-            final Resources.Theme lilacTheme = mResources.newTheme();
-            lilacTheme.applyStyle(R.style.LilacTheme, true);
-            final ColorStateList themedLilacColorStateList =
-                    ResourcesCompat.getColorStateList(mResources, R.color.complex_themed_selector,
-                            lilacTheme);
-            assertEquals("Themed lilac color state list load: default", 0xFFF080F0,
-                    themedLilacColorStateList.getDefaultColor());
-            assertEquals("Themed lilac color state list load: focused", 0xFFF070D0,
-                    themedLilacColorStateList.getColorForState(
-                            new int[]{android.R.attr.state_focused}, 0));
-            assertEquals("Themed lilac color state list load: pressed", 0xFFE070A0,
-                    themedLilacColorStateList.getColorForState(
-                            new int[]{android.R.attr.state_pressed}, 0));
-        }
-    }
-
-    @Test
-    public void testGetDrawable() throws Throwable {
-        final Drawable unthemedDrawable =
-                ResourcesCompat.getDrawable(mResources, R.drawable.test_drawable_red, null);
-        TestUtils.assertAllPixelsOfColor("Unthemed drawable load",
-                unthemedDrawable, mResources.getColor(R.color.test_red));
-
-        if (Build.VERSION.SDK_INT >= 23) {
-            // The following tests are only expected to pass on v23+ devices. The result of
-            // calling theme-aware getDrawable() in pre-v23 is undefined.
-            final Resources.Theme yellowTheme = mResources.newTheme();
-            yellowTheme.applyStyle(R.style.YellowTheme, true);
-            final Drawable themedYellowDrawable =
-                    ResourcesCompat.getDrawable(mResources, R.drawable.themed_drawable,
-                            yellowTheme);
-            TestUtils.assertAllPixelsOfColor("Themed yellow drawable load",
-                    themedYellowDrawable, 0xFFF0B000);
-
-            final Resources.Theme lilacTheme = mResources.newTheme();
-            lilacTheme.applyStyle(R.style.LilacTheme, true);
-            final Drawable themedLilacDrawable =
-                    ResourcesCompat.getDrawable(mResources, R.drawable.themed_drawable, lilacTheme);
-            TestUtils.assertAllPixelsOfColor("Themed lilac drawable load",
-                    themedLilacDrawable, 0xFFF080F0);
-        }
-    }
-
-    @Test(expected = Resources.NotFoundException.class)
-    public void testGetDrawableCannotDecode() {
-        ResourcesCompat.getDrawable(mResources, R.drawable.fake_image_will_not_decode, null);
-    }
-
-    @Test(expected = Resources.NotFoundException.class)
-    public void testGetDrawableForDensityCannotDecode() {
-        ResourcesCompat.getDrawableForDensity(mResources, R.drawable.fake_image_will_not_decode,
-                DisplayMetrics.DENSITY_MEDIUM, null);
-    }
-
-    @Test
-    public void testGetDrawableForDensityUnthemed() throws Throwable {
-        // Density-aware drawable loading for now only works on raw bitmap drawables.
-
-        // Different variants of density_aware_drawable are set up in the following way:
-        //    mdpi - 12x12 px which is 12x12 dip
-        //    hdpi - 21x21 px which is 14x14 dip
-        //   xhdpi - 32x32 px which is 16x16 dip
-        //  xxhdpi - 54x54 px which is 18x18 dip
-        // The tests below (on v15+ devices) are checking that an unthemed density-aware
-        // loading of raw bitmap drawables returns a drawable with matching intrinsic
-        // dimensions.
-
-        final Drawable unthemedDrawableForMediumDensity =
-                ResourcesCompat.getDrawableForDensity(mResources, R.drawable.density_aware_drawable,
-                        DisplayMetrics.DENSITY_MEDIUM, null);
-        // For pre-v15 devices we should get a drawable that corresponds to the density of the
-        // current device. For v15+ devices we should get a drawable that corresponds to the
-        // density requested in the API call.
-        final int expectedSizeForMediumDensity = (Build.VERSION.SDK_INT < 15) ?
-                mResources.getDimensionPixelSize(R.dimen.density_aware_size) : 12;
-        assertEquals("Unthemed density-aware drawable load: medium width",
-                expectedSizeForMediumDensity, unthemedDrawableForMediumDensity.getIntrinsicWidth());
-        assertEquals("Unthemed density-aware drawable load: medium height",
-                expectedSizeForMediumDensity,
-                unthemedDrawableForMediumDensity.getIntrinsicHeight());
-
-        final Drawable unthemedDrawableForHighDensity =
-                ResourcesCompat.getDrawableForDensity(mResources, R.drawable.density_aware_drawable,
-                        DisplayMetrics.DENSITY_HIGH, null);
-        // For pre-v15 devices we should get a drawable that corresponds to the density of the
-        // current device. For v15+ devices we should get a drawable that corresponds to the
-        // density requested in the API call.
-        final int expectedSizeForHighDensity = (Build.VERSION.SDK_INT < 15) ?
-                mResources.getDimensionPixelSize(R.dimen.density_aware_size) : 21;
-        assertEquals("Unthemed density-aware drawable load: high width",
-                expectedSizeForHighDensity, unthemedDrawableForHighDensity.getIntrinsicWidth());
-        assertEquals("Unthemed density-aware drawable load: high height",
-                expectedSizeForHighDensity, unthemedDrawableForHighDensity.getIntrinsicHeight());
-
-        final Drawable unthemedDrawableForXHighDensity =
-                ResourcesCompat.getDrawableForDensity(mResources, R.drawable.density_aware_drawable,
-                        DisplayMetrics.DENSITY_XHIGH, null);
-        // For pre-v15 devices we should get a drawable that corresponds to the density of the
-        // current device. For v15+ devices we should get a drawable that corresponds to the
-        // density requested in the API call.
-        final int expectedSizeForXHighDensity = (Build.VERSION.SDK_INT < 15) ?
-                mResources.getDimensionPixelSize(R.dimen.density_aware_size) : 32;
-        assertEquals("Unthemed density-aware drawable load: xhigh width",
-                expectedSizeForXHighDensity, unthemedDrawableForXHighDensity.getIntrinsicWidth());
-        assertEquals("Unthemed density-aware drawable load: xhigh height",
-                expectedSizeForXHighDensity, unthemedDrawableForXHighDensity.getIntrinsicHeight());
-
-        final Drawable unthemedDrawableForXXHighDensity =
-                ResourcesCompat.getDrawableForDensity(mResources, R.drawable.density_aware_drawable,
-                        DisplayMetrics.DENSITY_XXHIGH, null);
-        // For pre-v15 devices we should get a drawable that corresponds to the density of the
-        // current device. For v15+ devices we should get a drawable that corresponds to the
-        // density requested in the API call.
-        final int expectedSizeForXXHighDensity = (Build.VERSION.SDK_INT < 15) ?
-                mResources.getDimensionPixelSize(R.dimen.density_aware_size) : 54;
-        assertEquals("Unthemed density-aware drawable load: xxhigh width",
-                expectedSizeForXXHighDensity, unthemedDrawableForXXHighDensity.getIntrinsicWidth());
-        assertEquals("Unthemed density-aware drawable load: xxhigh height",
-                expectedSizeForXXHighDensity,
-                unthemedDrawableForXXHighDensity.getIntrinsicHeight());
-    }
-
-    @Test
-    public void testGetDrawableForDensityThemed() throws Throwable {
-        if (Build.VERSION.SDK_INT < 21) {
-            // The following tests are only expected to pass on v21+ devices. The result of
-            // calling theme-aware getDrawableForDensity() in pre-v21 is undefined.
-            return;
-        }
-
-        // Density- and theme-aware drawable loading for now only works partially. This test
-        // checks only for theming of a tinted bitmap XML drawable, but not correct scaling.
-
-        // Set up the two test themes, yellow and lilac.
-        final Resources.Theme yellowTheme = mResources.newTheme();
-        yellowTheme.applyStyle(R.style.YellowTheme, true);
-
-        final Resources.Theme lilacTheme = mResources.newTheme();
-        lilacTheme.applyStyle(R.style.LilacTheme, true);
-
-        Drawable themedYellowDrawableForMediumDensity =
-                ResourcesCompat.getDrawableForDensity(mResources, R.drawable.themed_bitmap,
-                        DisplayMetrics.DENSITY_MEDIUM, yellowTheme);
-        // We should get a drawable that corresponds to the theme requested in the API call.
-        TestUtils.assertAllPixelsOfColor("Themed yellow density-aware drawable load : medium color",
-                themedYellowDrawableForMediumDensity, 0xFFF0B000);
-
-        Drawable themedLilacDrawableForMediumDensity =
-                ResourcesCompat.getDrawableForDensity(mResources, R.drawable.themed_bitmap,
-                        DisplayMetrics.DENSITY_MEDIUM, lilacTheme);
-        // We should get a drawable that corresponds to the theme requested in the API call.
-        TestUtils.assertAllPixelsOfColor("Themed lilac density-aware drawable load : medium color",
-                themedLilacDrawableForMediumDensity, 0xFFF080F0);
-
-        Drawable themedYellowDrawableForHighDensity =
-                ResourcesCompat.getDrawableForDensity(mResources, R.drawable.themed_bitmap,
-                        DisplayMetrics.DENSITY_HIGH, yellowTheme);
-        // We should get a drawable that corresponds to the theme requested in the API call.
-        TestUtils.assertAllPixelsOfColor("Themed yellow density-aware drawable load : high color",
-                themedYellowDrawableForHighDensity, 0xFFF0B000);
-
-        Drawable themedLilacDrawableForHighDensity =
-                ResourcesCompat.getDrawableForDensity(mResources, R.drawable.themed_bitmap,
-                        DisplayMetrics.DENSITY_HIGH, lilacTheme);
-        // We should get a drawable that corresponds to the theme requested in the API call.
-        TestUtils.assertAllPixelsOfColor("Themed lilac density-aware drawable load : high color",
-                themedLilacDrawableForHighDensity, 0xFFF080F0);
-
-        Drawable themedYellowDrawableForXHighDensity =
-                ResourcesCompat.getDrawableForDensity(mResources, R.drawable.themed_bitmap,
-                        DisplayMetrics.DENSITY_XHIGH, yellowTheme);
-        // We should get a drawable that corresponds to the theme requested in the API call.
-        TestUtils.assertAllPixelsOfColor("Themed yellow density-aware drawable load : xhigh color",
-                themedYellowDrawableForXHighDensity, 0xFFF0B000);
-
-        Drawable themedLilacDrawableForXHighDensity =
-                ResourcesCompat.getDrawableForDensity(mResources, R.drawable.themed_bitmap,
-                        DisplayMetrics.DENSITY_XHIGH, lilacTheme);
-        // We should get a drawable that corresponds to the theme requested in the API call.
-        TestUtils.assertAllPixelsOfColor("Themed lilac density-aware drawable load : xhigh color",
-                themedLilacDrawableForXHighDensity, 0xFFF080F0);
-
-        Drawable themedYellowDrawableForXXHighDensity =
-                ResourcesCompat.getDrawableForDensity(mResources, R.drawable.themed_bitmap,
-                        DisplayMetrics.DENSITY_XXHIGH, yellowTheme);
-        // We should get a drawable that corresponds to the theme requested in the API call.
-        TestUtils.assertAllPixelsOfColor("Themed yellow density-aware drawable load : xxhigh color",
-                themedYellowDrawableForXXHighDensity, 0xFFF0B000);
-
-        Drawable themedLilacDrawableForXXHighDensity =
-                ResourcesCompat.getDrawableForDensity(mResources, R.drawable.themed_bitmap,
-                        DisplayMetrics.DENSITY_XXHIGH, lilacTheme);
-        // We should get a drawable that corresponds to the theme requested in the API call.
-        TestUtils.assertAllPixelsOfColor("Themed lilac density-aware drawable load : xxhigh color",
-                themedLilacDrawableForXXHighDensity, 0xFFF080F0);
-    }
-
-    @Test(expected = Resources.NotFoundException.class)
-    public void testGetFont_invalidResourceId() {
-        ResourcesCompat.getFont(mContext, -1);
-    }
-
-    @Test
-    public void testGetFont_fontFile_sync() {
-        Typeface font = ResourcesCompat.getFont(mContext, R.font.samplefont);
-
-        assertNotNull(font);
-        assertNotSame(Typeface.DEFAULT, font);
-    }
-
-    private static final 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 testGetFont_fontFile_async() throws InterruptedException {
-        final CountDownLatch latch = new CountDownLatch(1);
-        final FontCallback callback = new FontCallback(latch);
-        FontsContractCompat.resetCache();
-
-        ResourcesCompat.getFont(mContext, R.font.samplefont, callback, null);
-
-        assertTrue(latch.await(5L, TimeUnit.SECONDS));
-
-        assertNotNull(callback.mTypeface);
-        assertNotSame(Typeface.DEFAULT, callback.mTypeface);
-    }
-
-    @Test
-    public void testGetFont_xmlFile_sync() {
-        Typeface font = ResourcesCompat.getFont(mContext, R.font.samplexmlfont);
-
-        assertNotNull(font);
-        assertNotSame(Typeface.DEFAULT, font);
-    }
-
-    @Test
-    public void testGetFont_xmlFile_async() throws InterruptedException {
-        final CountDownLatch latch = new CountDownLatch(1);
-        final FontCallback callback = new FontCallback(latch);
-
-        ResourcesCompat.getFont(mContext, R.font.samplexmlfont, callback, null);
-
-        assertTrue(latch.await(5L, TimeUnit.SECONDS));
-
-        assertNotNull(callback.mTypeface);
-        assertNotSame(Typeface.DEFAULT, callback.mTypeface);
-    }
-
-    @Test
-    public void testGetFont_xmlProviderFile_sync() {
-        Typeface font = ResourcesCompat.getFont(mContext, R.font.samplexmldownloadedfont);
-
-        assertNotNull(font);
-        assertNotSame(Typeface.DEFAULT, font);
-    }
-
-    @Test
-    public void testGetFont_xmlProviderFile_async() throws InterruptedException {
-        final CountDownLatch latch = new CountDownLatch(1);
-        final FontCallback callback = new FontCallback(latch);
-
-        // Font provider non-blocking requests post on the calling thread so can't run on
-        // the test thread as it doesn't have a Looper.
-        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                ResourcesCompat.getFont(mContext, R.font.samplexmldownloadedfont, callback, null);
-            }
-        });
-
-        assertTrue(latch.await(5L, TimeUnit.SECONDS));
-
-        assertNotNull(callback.mTypeface);
-        assertNotSame(Typeface.DEFAULT, callback.mTypeface);
-    }
-
-    @Test
-    public void testGetFont_invalidXmlFile() {
-        try {
-            assertNull(
-                    ResourcesCompat.getFont(mContext, R.font.invalid_xmlfamily));
-        } catch (Resources.NotFoundException e) {
-            // pass
-        }
-
-        try {
-            assertNull(ResourcesCompat.getFont(mContext, R.font.invalid_xmlempty));
-        } catch (Resources.NotFoundException e) {
-            // pass
-        }
-    }
-
-    @Test
-    public void testGetFont_fontFileIsCached() {
-        Typeface font = ResourcesCompat.getFont(mContext, R.font.samplefont);
-        Typeface font2 = ResourcesCompat.getFont(mContext, R.font.samplefont);
-
-        assertSame(font, font2);
-    }
-
-    @Test
-    public void testGetFont_xmlFileIsCached() {
-        Typeface font = ResourcesCompat.getFont(mContext, R.font.samplexmlfont);
-        Typeface font2 = ResourcesCompat.getFont(mContext, R.font.samplexmlfont);
-
-        assertSame(font, font2);
-    }
-}
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/LongSparseArrayTest.java b/compat/tests/java/android/support/v4/util/LongSparseArrayTest.java
deleted file mode 100644
index 663ea48..0000000
--- a/compat/tests/java/android/support/v4/util/LongSparseArrayTest.java
+++ /dev/null
@@ -1,59 +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.util;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-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/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/compat/tests/java/android/support/v4/util/SparseArrayCompatTest.java b/compat/tests/java/android/support/v4/util/SparseArrayCompatTest.java
deleted file mode 100644
index 122c89b..0000000
--- a/compat/tests/java/android/support/v4/util/SparseArrayCompatTest.java
+++ /dev/null
@@ -1,58 +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.util;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-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/tests/java/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatTest.java b/compat/tests/java/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatTest.java
deleted file mode 100644
index 34a0f99..0000000
--- a/compat/tests/java/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatTest.java
+++ /dev/null
@@ -1,46 +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.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/tests/res/drawable/fake_image_will_not_decode.jpg b/compat/tests/res/drawable/fake_image_will_not_decode.jpg
deleted file mode 100644
index 32f7531..0000000
--- a/compat/tests/res/drawable/fake_image_will_not_decode.jpg
+++ /dev/null
@@ -1 +0,0 @@
-lol not a jpg
\ No newline at end of file
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/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..9369e79
--- /dev/null
+++ b/coordinatorlayout/src/main/java/android/support/design/widget/CoordinatorLayout.java
@@ -0,0 +1,3296 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.AttrRes;
+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(@NonNull Context context) {
+        this(context, null);
+    }
+
+    public CoordinatorLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
+        this(context, attrs, R.attr.coordinatorLayoutStyle);
+    }
+
+    public CoordinatorLayout(@NonNull Context context, @Nullable AttributeSet attrs,
+            @AttrRes 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) {
+        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 (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(@NonNull 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 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(@NonNull 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(@NonNull 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(@NonNull View first, @NonNull 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(@NonNull CoordinatorLayout parent, @NonNull V child,
+                @NonNull 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(@NonNull CoordinatorLayout parent, @NonNull V child,
+                @NonNull 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(@NonNull CoordinatorLayout parent, @NonNull 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(@NonNull CoordinatorLayout parent, @NonNull 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(@NonNull CoordinatorLayout parent, @NonNull 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(@NonNull CoordinatorLayout parent, @NonNull V child,
+                @NonNull 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(@NonNull CoordinatorLayout parent, @NonNull V child,
+                @NonNull 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(@NonNull CoordinatorLayout parent, @NonNull V child,
+                @NonNull 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(@NonNull CoordinatorLayout parent, @NonNull 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(@NonNull CoordinatorLayout parent, @NonNull 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(@NonNull View child, @Nullable 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
+         */
+        @Nullable
+        public static Object getTag(@NonNull 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(@NonNull CoordinatorLayout coordinatorLayout,
+                @NonNull V child, @NonNull 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(@NonNull CoordinatorLayout coordinatorLayout,
+                @NonNull V child, @NonNull 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(@NonNull CoordinatorLayout parent, @NonNull V child,
+                @NonNull 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()
+         */
+        @Nullable
+        public Parcelable onSaveInstanceState(@NonNull CoordinatorLayout parent, @NonNull 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(@NonNull Context context, @Nullable 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/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/AndroidManifest.xml b/core-ui/src/main/AndroidManifest.xml
similarity index 100%
rename from core-ui/AndroidManifest.xml
rename to core-ui/src/main/AndroidManifest.xml
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/view/ViewPager.java b/core-ui/src/main/java/android/support/v4/view/ViewPager.java
deleted file mode 100644
index 350fe95..0000000
--- a/core-ui/src/main/java/android/support/v4/view/ViewPager.java
+++ /dev/null
@@ -1,3162 +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.view;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.database.DataSetObserver;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.SystemClock;
-import android.support.annotation.CallSuper;
-import android.support.annotation.DrawableRes;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v4.content.ContextCompat;
-import android.support.v4.view.accessibility.AccessibilityEventCompat;
-import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.FocusFinder;
-import android.view.Gravity;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.SoundEffectConstants;
-import android.view.VelocityTracker;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewGroup;
-import android.view.ViewParent;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.animation.Interpolator;
-import android.widget.EdgeEffect;
-import android.widget.Scroller;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Inherited;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-
-/**
- * Layout manager that allows the user to flip left and right
- * through pages of data.  You supply an implementation of a
- * {@link PagerAdapter} to generate the pages that the view shows.
- *
- * <p>ViewPager is most often used in conjunction with {@link android.app.Fragment},
- * which is a convenient way to supply and manage the lifecycle of each page.
- * There are standard adapters implemented for using fragments with the ViewPager,
- * which cover the most common use cases.  These are
- * {@link android.support.v4.app.FragmentPagerAdapter} and
- * {@link android.support.v4.app.FragmentStatePagerAdapter}; each of these
- * classes have simple code showing how to build a full user interface
- * with them.
- *
- * <p>Views which are annotated with the {@link DecorView} annotation are treated as
- * part of the view pagers 'decor'. Each decor view's position can be controlled via
- * its {@code android:layout_gravity} attribute. For example:
- *
- * <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.v4.view.PagerTitleStrip
- *         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>
- *
- * <p>For more information about how to use ViewPager, read <a
- * href="{@docRoot}training/implementing-navigation/lateral.html">Creating Swipe Views with
- * Tabs</a>.</p>
- *
- * <p>You can find examples of using ViewPager in the API 4+ Support Demos and API 13+ Support Demos
- * sample code.
- */
-public class ViewPager extends ViewGroup {
-    private static final String TAG = "ViewPager";
-    private static final boolean DEBUG = false;
-
-    private static final boolean USE_CACHE = false;
-
-    private static final int DEFAULT_OFFSCREEN_PAGES = 1;
-    private static final int MAX_SETTLE_DURATION = 600; // ms
-    private static final int MIN_DISTANCE_FOR_FLING = 25; // dips
-
-    private static final int DEFAULT_GUTTER_SIZE = 16; // dips
-
-    private static final int MIN_FLING_VELOCITY = 400; // dips
-
-    static final int[] LAYOUT_ATTRS = new int[] {
-        android.R.attr.layout_gravity
-    };
-
-    /**
-     * Used to track what the expected number of items in the adapter should be.
-     * If the app changes this when we don't expect it, we'll throw a big obnoxious exception.
-     */
-    private int mExpectedAdapterCount;
-
-    static class ItemInfo {
-        Object object;
-        int position;
-        boolean scrolling;
-        float widthFactor;
-        float offset;
-    }
-
-    private static final Comparator<ItemInfo> COMPARATOR = new Comparator<ItemInfo>(){
-        @Override
-        public int compare(ItemInfo lhs, ItemInfo rhs) {
-            return lhs.position - rhs.position;
-        }
-    };
-
-    private static final Interpolator sInterpolator = new Interpolator() {
-        @Override
-        public float getInterpolation(float t) {
-            t -= 1.0f;
-            return t * t * t * t * t + 1.0f;
-        }
-    };
-
-    private final ArrayList<ItemInfo> mItems = new ArrayList<ItemInfo>();
-    private final ItemInfo mTempItem = new ItemInfo();
-
-    private final Rect mTempRect = new Rect();
-
-    PagerAdapter mAdapter;
-    int mCurItem;   // Index of currently displayed page.
-    private int mRestoredCurItem = -1;
-    private Parcelable mRestoredAdapterState = null;
-    private ClassLoader mRestoredClassLoader = null;
-
-    private Scroller mScroller;
-    private boolean mIsScrollStarted;
-
-    private PagerObserver mObserver;
-
-    private int mPageMargin;
-    private Drawable mMarginDrawable;
-    private int mTopPageBounds;
-    private int mBottomPageBounds;
-
-    // Offsets of the first and last items, if known.
-    // Set during population, used to determine if we are at the beginning
-    // or end of the pager data set during touch scrolling.
-    private float mFirstOffset = -Float.MAX_VALUE;
-    private float mLastOffset = Float.MAX_VALUE;
-
-    private int mChildWidthMeasureSpec;
-    private int mChildHeightMeasureSpec;
-    private boolean mInLayout;
-
-    private boolean mScrollingCacheEnabled;
-
-    private boolean mPopulatePending;
-    private int mOffscreenPageLimit = DEFAULT_OFFSCREEN_PAGES;
-
-    private boolean mIsBeingDragged;
-    private boolean mIsUnableToDrag;
-    private int mDefaultGutterSize;
-    private int mGutterSize;
-    private int mTouchSlop;
-    /**
-     * Position of the last motion event.
-     */
-    private float mLastMotionX;
-    private float mLastMotionY;
-    private float mInitialMotionX;
-    private float mInitialMotionY;
-    /**
-     * ID of the active pointer. This is used to retain consistency during
-     * drags/flings if multiple pointers are used.
-     */
-    private int mActivePointerId = INVALID_POINTER;
-    /**
-     * Sentinel value for no current active pointer.
-     * Used by {@link #mActivePointerId}.
-     */
-    private static final int INVALID_POINTER = -1;
-
-    /**
-     * Determines speed during touch scrolling
-     */
-    private VelocityTracker mVelocityTracker;
-    private int mMinimumVelocity;
-    private int mMaximumVelocity;
-    private int mFlingDistance;
-    private int mCloseEnough;
-
-    // If the pager is at least this close to its final position, complete the scroll
-    // on touch down and let the user interact with the content inside instead of
-    // "catching" the flinging pager.
-    private static final int CLOSE_ENOUGH = 2; // dp
-
-    private boolean mFakeDragging;
-    private long mFakeDragBeginTime;
-
-    private EdgeEffect mLeftEdge;
-    private EdgeEffect mRightEdge;
-
-    private boolean mFirstLayout = true;
-    private boolean mNeedCalculatePageOffsets = false;
-    private boolean mCalledSuper;
-    private int mDecorChildCount;
-
-    private List<OnPageChangeListener> mOnPageChangeListeners;
-    private OnPageChangeListener mOnPageChangeListener;
-    private OnPageChangeListener mInternalPageChangeListener;
-    private List<OnAdapterChangeListener> mAdapterChangeListeners;
-    private PageTransformer mPageTransformer;
-    private int mPageTransformerLayerType;
-
-    private static final int DRAW_ORDER_DEFAULT = 0;
-    private static final int DRAW_ORDER_FORWARD = 1;
-    private static final int DRAW_ORDER_REVERSE = 2;
-    private int mDrawingOrder;
-    private ArrayList<View> mDrawingOrderedChildren;
-    private static final ViewPositionComparator sPositionComparator = new ViewPositionComparator();
-
-    /**
-     * Indicates that the pager is in an idle, settled state. The current page
-     * is fully in view and no animation is in progress.
-     */
-    public static final int SCROLL_STATE_IDLE = 0;
-
-    /**
-     * Indicates that the pager is currently being dragged by the user.
-     */
-    public static final int SCROLL_STATE_DRAGGING = 1;
-
-    /**
-     * Indicates that the pager is in the process of settling to a final position.
-     */
-    public static final int SCROLL_STATE_SETTLING = 2;
-
-    private final Runnable mEndScrollRunnable = new Runnable() {
-        @Override
-        public void run() {
-            setScrollState(SCROLL_STATE_IDLE);
-            populate();
-        }
-    };
-
-    private int mScrollState = SCROLL_STATE_IDLE;
-
-    /**
-     * Callback interface for responding to changing state of the selected page.
-     */
-    public interface OnPageChangeListener {
-
-        /**
-         * This method will be invoked when the current page is scrolled, either as part
-         * of a programmatically initiated smooth scroll or a user initiated touch scroll.
-         *
-         * @param position Position index of the first page currently being displayed.
-         *                 Page position+1 will be visible if positionOffset is nonzero.
-         * @param positionOffset Value from [0, 1) indicating the offset from the page at position.
-         * @param positionOffsetPixels Value in pixels indicating the offset from position.
-         */
-        void onPageScrolled(int position, float positionOffset, int positionOffsetPixels);
-
-        /**
-         * This method will be invoked when a new page becomes selected. Animation is not
-         * necessarily complete.
-         *
-         * @param position Position index of the new selected page.
-         */
-        void onPageSelected(int position);
-
-        /**
-         * Called when the scroll state changes. Useful for discovering when the user
-         * begins dragging, when the pager is automatically settling to the current page,
-         * or when it is fully stopped/idle.
-         *
-         * @param state The new scroll state.
-         * @see ViewPager#SCROLL_STATE_IDLE
-         * @see ViewPager#SCROLL_STATE_DRAGGING
-         * @see ViewPager#SCROLL_STATE_SETTLING
-         */
-        void onPageScrollStateChanged(int state);
-    }
-
-    /**
-     * Simple implementation of the {@link OnPageChangeListener} interface with stub
-     * implementations of each method. Extend this if you do not intend to override
-     * every method of {@link OnPageChangeListener}.
-     */
-    public static class SimpleOnPageChangeListener implements OnPageChangeListener {
-        @Override
-        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
-            // This space for rent
-        }
-
-        @Override
-        public void onPageSelected(int position) {
-            // This space for rent
-        }
-
-        @Override
-        public void onPageScrollStateChanged(int state) {
-            // This space for rent
-        }
-    }
-
-    /**
-     * A PageTransformer is invoked whenever a visible/attached page is scrolled.
-     * This offers an opportunity for the application to apply a custom transformation
-     * to the page views using animation properties.
-     *
-     * <p>As property animation is only supported as of Android 3.0 and forward,
-     * setting a PageTransformer on a ViewPager on earlier platform versions will
-     * be ignored.</p>
-     */
-    public interface PageTransformer {
-        /**
-         * Apply a property transformation to the given page.
-         *
-         * @param page Apply the transformation to this page
-         * @param position Position of page relative to the current front-and-center
-         *                 position of the pager. 0 is front and center. 1 is one full
-         *                 page position to the right, and -1 is one page position to the left.
-         */
-        void transformPage(@NonNull View page, float position);
-    }
-
-    /**
-     * Callback interface for responding to adapter changes.
-     */
-    public interface OnAdapterChangeListener {
-        /**
-         * Called when the adapter for the given view pager has changed.
-         *
-         * @param viewPager  ViewPager where the adapter change has happened
-         * @param oldAdapter the previously set adapter
-         * @param newAdapter the newly set adapter
-         */
-        void onAdapterChanged(@NonNull ViewPager viewPager,
-                @Nullable PagerAdapter oldAdapter, @Nullable PagerAdapter newAdapter);
-    }
-
-    /**
-     * Annotation which allows marking of views to be decoration views when added to a view
-     * pager.
-     *
-     * <p>Views marked with this annotation can be added to the view pager with a layout resource.
-     * An example being {@link PagerTitleStrip}.</p>
-     *
-     * <p>You can also control whether a view is a decor view but setting
-     * {@link LayoutParams#isDecor} on the child's layout params.</p>
-     */
-    @Retention(RetentionPolicy.RUNTIME)
-    @Target(ElementType.TYPE)
-    @Inherited
-    public @interface DecorView {
-    }
-
-    public ViewPager(@NonNull Context context) {
-        super(context);
-        initViewPager();
-    }
-
-    public ViewPager(@NonNull Context context, @Nullable AttributeSet attrs) {
-        super(context, attrs);
-        initViewPager();
-    }
-
-    void initViewPager() {
-        setWillNotDraw(false);
-        setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
-        setFocusable(true);
-        final Context context = getContext();
-        mScroller = new Scroller(context, sInterpolator);
-        final ViewConfiguration configuration = ViewConfiguration.get(context);
-        final float density = context.getResources().getDisplayMetrics().density;
-
-        mTouchSlop = configuration.getScaledPagingTouchSlop();
-        mMinimumVelocity = (int) (MIN_FLING_VELOCITY * density);
-        mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
-        mLeftEdge = new EdgeEffect(context);
-        mRightEdge = new EdgeEffect(context);
-
-        mFlingDistance = (int) (MIN_DISTANCE_FOR_FLING * density);
-        mCloseEnough = (int) (CLOSE_ENOUGH * density);
-        mDefaultGutterSize = (int) (DEFAULT_GUTTER_SIZE * density);
-
-        ViewCompat.setAccessibilityDelegate(this, new MyAccessibilityDelegate());
-
-        if (ViewCompat.getImportantForAccessibility(this)
-                == ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
-            ViewCompat.setImportantForAccessibility(this,
-                    ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
-        }
-
-        ViewCompat.setOnApplyWindowInsetsListener(this,
-                new android.support.v4.view.OnApplyWindowInsetsListener() {
-                    private final Rect mTempRect = new Rect();
-
-                    @Override
-                    public WindowInsetsCompat onApplyWindowInsets(final View v,
-                            final WindowInsetsCompat originalInsets) {
-                        // First let the ViewPager itself try and consume them...
-                        final WindowInsetsCompat applied =
-                                ViewCompat.onApplyWindowInsets(v, originalInsets);
-                        if (applied.isConsumed()) {
-                            // If the ViewPager consumed all insets, return now
-                            return applied;
-                        }
-
-                        // Now we'll manually dispatch the insets to our children. Since ViewPager
-                        // children are always full-height, we do not want to use the standard
-                        // ViewGroup dispatchApplyWindowInsets since if child 0 consumes them,
-                        // the rest of the children will not receive any insets. To workaround this
-                        // we manually dispatch the applied insets, not allowing children to
-                        // consume them from each other. We do however keep track of any insets
-                        // which are consumed, returning the union of our children's consumption
-                        final Rect res = mTempRect;
-                        res.left = applied.getSystemWindowInsetLeft();
-                        res.top = applied.getSystemWindowInsetTop();
-                        res.right = applied.getSystemWindowInsetRight();
-                        res.bottom = applied.getSystemWindowInsetBottom();
-
-                        for (int i = 0, count = getChildCount(); i < count; i++) {
-                            final WindowInsetsCompat childInsets = ViewCompat
-                                    .dispatchApplyWindowInsets(getChildAt(i), applied);
-                            // Now keep track of any consumed by tracking each dimension's min
-                            // value
-                            res.left = Math.min(childInsets.getSystemWindowInsetLeft(),
-                                    res.left);
-                            res.top = Math.min(childInsets.getSystemWindowInsetTop(),
-                                    res.top);
-                            res.right = Math.min(childInsets.getSystemWindowInsetRight(),
-                                    res.right);
-                            res.bottom = Math.min(childInsets.getSystemWindowInsetBottom(),
-                                    res.bottom);
-                        }
-
-                        // Now return a new WindowInsets, using the consumed window insets
-                        return applied.replaceSystemWindowInsets(
-                                res.left, res.top, res.right, res.bottom);
-                    }
-                });
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        removeCallbacks(mEndScrollRunnable);
-        // To be on the safe side, abort the scroller
-        if ((mScroller != null) && !mScroller.isFinished()) {
-            mScroller.abortAnimation();
-        }
-        super.onDetachedFromWindow();
-    }
-
-    void setScrollState(int newState) {
-        if (mScrollState == newState) {
-            return;
-        }
-
-        mScrollState = newState;
-        if (mPageTransformer != null) {
-            // PageTransformers can do complex things that benefit from hardware layers.
-            enableLayers(newState != SCROLL_STATE_IDLE);
-        }
-        dispatchOnScrollStateChanged(newState);
-    }
-
-    /**
-     * Set a PagerAdapter that will supply views for this pager as needed.
-     *
-     * @param adapter Adapter to use
-     */
-    public void setAdapter(@Nullable PagerAdapter adapter) {
-        if (mAdapter != null) {
-            mAdapter.setViewPagerObserver(null);
-            mAdapter.startUpdate(this);
-            for (int i = 0; i < mItems.size(); i++) {
-                final ItemInfo ii = mItems.get(i);
-                mAdapter.destroyItem(this, ii.position, ii.object);
-            }
-            mAdapter.finishUpdate(this);
-            mItems.clear();
-            removeNonDecorViews();
-            mCurItem = 0;
-            scrollTo(0, 0);
-        }
-
-        final PagerAdapter oldAdapter = mAdapter;
-        mAdapter = adapter;
-        mExpectedAdapterCount = 0;
-
-        if (mAdapter != null) {
-            if (mObserver == null) {
-                mObserver = new PagerObserver();
-            }
-            mAdapter.setViewPagerObserver(mObserver);
-            mPopulatePending = false;
-            final boolean wasFirstLayout = mFirstLayout;
-            mFirstLayout = true;
-            mExpectedAdapterCount = mAdapter.getCount();
-            if (mRestoredCurItem >= 0) {
-                mAdapter.restoreState(mRestoredAdapterState, mRestoredClassLoader);
-                setCurrentItemInternal(mRestoredCurItem, false, true);
-                mRestoredCurItem = -1;
-                mRestoredAdapterState = null;
-                mRestoredClassLoader = null;
-            } else if (!wasFirstLayout) {
-                populate();
-            } else {
-                requestLayout();
-            }
-        }
-
-        // Dispatch the change to any listeners
-        if (mAdapterChangeListeners != null && !mAdapterChangeListeners.isEmpty()) {
-            for (int i = 0, count = mAdapterChangeListeners.size(); i < count; i++) {
-                mAdapterChangeListeners.get(i).onAdapterChanged(this, oldAdapter, adapter);
-            }
-        }
-    }
-
-    private void removeNonDecorViews() {
-        for (int i = 0; i < getChildCount(); i++) {
-            final View child = getChildAt(i);
-            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-            if (!lp.isDecor) {
-                removeViewAt(i);
-                i--;
-            }
-        }
-    }
-
-    /**
-     * Retrieve the current adapter supplying pages.
-     *
-     * @return The currently registered PagerAdapter
-     */
-    @Nullable
-    public PagerAdapter getAdapter() {
-        return mAdapter;
-    }
-
-    /**
-     * Add a listener that will be invoked whenever the adapter for this ViewPager changes.
-     *
-     * @param listener listener to add
-     */
-    public void addOnAdapterChangeListener(@NonNull OnAdapterChangeListener listener) {
-        if (mAdapterChangeListeners == null) {
-            mAdapterChangeListeners = new ArrayList<>();
-        }
-        mAdapterChangeListeners.add(listener);
-    }
-
-    /**
-     * Remove a listener that was previously added via
-     * {@link #addOnAdapterChangeListener(OnAdapterChangeListener)}.
-     *
-     * @param listener listener to remove
-     */
-    public void removeOnAdapterChangeListener(@NonNull OnAdapterChangeListener listener) {
-        if (mAdapterChangeListeners != null) {
-            mAdapterChangeListeners.remove(listener);
-        }
-    }
-
-    private int getClientWidth() {
-        return getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
-    }
-
-    /**
-     * Set the currently selected page. If the ViewPager has already been through its first
-     * layout with its current adapter there will be a smooth animated transition between
-     * the current item and the specified item.
-     *
-     * @param item Item index to select
-     */
-    public void setCurrentItem(int item) {
-        mPopulatePending = false;
-        setCurrentItemInternal(item, !mFirstLayout, false);
-    }
-
-    /**
-     * Set the currently selected page.
-     *
-     * @param item Item index to select
-     * @param smoothScroll True to smoothly scroll to the new item, false to transition immediately
-     */
-    public void setCurrentItem(int item, boolean smoothScroll) {
-        mPopulatePending = false;
-        setCurrentItemInternal(item, smoothScroll, false);
-    }
-
-    public int getCurrentItem() {
-        return mCurItem;
-    }
-
-    void setCurrentItemInternal(int item, boolean smoothScroll, boolean always) {
-        setCurrentItemInternal(item, smoothScroll, always, 0);
-    }
-
-    void setCurrentItemInternal(int item, boolean smoothScroll, boolean always, int velocity) {
-        if (mAdapter == null || mAdapter.getCount() <= 0) {
-            setScrollingCacheEnabled(false);
-            return;
-        }
-        if (!always && mCurItem == item && mItems.size() != 0) {
-            setScrollingCacheEnabled(false);
-            return;
-        }
-
-        if (item < 0) {
-            item = 0;
-        } else if (item >= mAdapter.getCount()) {
-            item = mAdapter.getCount() - 1;
-        }
-        final int pageLimit = mOffscreenPageLimit;
-        if (item > (mCurItem + pageLimit) || item < (mCurItem - pageLimit)) {
-            // We are doing a jump by more than one page.  To avoid
-            // glitches, we want to keep all current pages in the view
-            // until the scroll ends.
-            for (int i = 0; i < mItems.size(); i++) {
-                mItems.get(i).scrolling = true;
-            }
-        }
-        final boolean dispatchSelected = mCurItem != item;
-
-        if (mFirstLayout) {
-            // We don't have any idea how big we are yet and shouldn't have any pages either.
-            // Just set things up and let the pending layout handle things.
-            mCurItem = item;
-            if (dispatchSelected) {
-                dispatchOnPageSelected(item);
-            }
-            requestLayout();
-        } else {
-            populate(item);
-            scrollToItem(item, smoothScroll, velocity, dispatchSelected);
-        }
-    }
-
-    private void scrollToItem(int item, boolean smoothScroll, int velocity,
-            boolean dispatchSelected) {
-        final ItemInfo curInfo = infoForPosition(item);
-        int destX = 0;
-        if (curInfo != null) {
-            final int width = getClientWidth();
-            destX = (int) (width * Math.max(mFirstOffset,
-                    Math.min(curInfo.offset, mLastOffset)));
-        }
-        if (smoothScroll) {
-            smoothScrollTo(destX, 0, velocity);
-            if (dispatchSelected) {
-                dispatchOnPageSelected(item);
-            }
-        } else {
-            if (dispatchSelected) {
-                dispatchOnPageSelected(item);
-            }
-            completeScroll(false);
-            scrollTo(destX, 0);
-            pageScrolled(destX);
-        }
-    }
-
-    /**
-     * Set a listener that will be invoked whenever the page changes or is incrementally
-     * scrolled. See {@link OnPageChangeListener}.
-     *
-     * @param listener Listener to set
-     *
-     * @deprecated Use {@link #addOnPageChangeListener(OnPageChangeListener)}
-     * and {@link #removeOnPageChangeListener(OnPageChangeListener)} instead.
-     */
-    @Deprecated
-    public void setOnPageChangeListener(OnPageChangeListener listener) {
-        mOnPageChangeListener = listener;
-    }
-
-    /**
-     * Add a listener that will be invoked whenever the page changes or is incrementally
-     * scrolled. See {@link OnPageChangeListener}.
-     *
-     * <p>Components that add a listener should take care to remove it when finished.
-     * Other components that take ownership of a view may call {@link #clearOnPageChangeListeners()}
-     * to remove all attached listeners.</p>
-     *
-     * @param listener listener to add
-     */
-    public void addOnPageChangeListener(@NonNull OnPageChangeListener listener) {
-        if (mOnPageChangeListeners == null) {
-            mOnPageChangeListeners = new ArrayList<>();
-        }
-        mOnPageChangeListeners.add(listener);
-    }
-
-    /**
-     * Remove a listener that was previously added via
-     * {@link #addOnPageChangeListener(OnPageChangeListener)}.
-     *
-     * @param listener listener to remove
-     */
-    public void removeOnPageChangeListener(@NonNull OnPageChangeListener listener) {
-        if (mOnPageChangeListeners != null) {
-            mOnPageChangeListeners.remove(listener);
-        }
-    }
-
-    /**
-     * Remove all listeners that are notified of any changes in scroll state or position.
-     */
-    public void clearOnPageChangeListeners() {
-        if (mOnPageChangeListeners != null) {
-            mOnPageChangeListeners.clear();
-        }
-    }
-
-    /**
-     * Sets a {@link PageTransformer} that will be called for each attached page whenever
-     * the scroll position is changed. This allows the application to apply custom property
-     * transformations to each page, overriding the default sliding behavior.
-     *
-     * <p><em>Note:</em> By default, calling this method will cause contained pages to use
-     * {@link View#LAYER_TYPE_HARDWARE}. This layer type allows custom alpha transformations,
-     * but it will cause issues if any of your pages contain a {@link android.view.SurfaceView}
-     * and you have not called {@link android.view.SurfaceView#setZOrderOnTop(boolean)} to put that
-     * {@link android.view.SurfaceView} above your app content. To disable this behavior, call
-     * {@link #setPageTransformer(boolean,PageTransformer,int)} and pass
-     * {@link View#LAYER_TYPE_NONE} for {@code pageLayerType}.</p>
-     *
-     * @param reverseDrawingOrder true if the supplied PageTransformer requires page views
-     *                            to be drawn from last to first instead of first to last.
-     * @param transformer PageTransformer that will modify each page's animation properties
-     */
-    public void setPageTransformer(boolean reverseDrawingOrder,
-            @Nullable PageTransformer transformer) {
-        setPageTransformer(reverseDrawingOrder, transformer, View.LAYER_TYPE_HARDWARE);
-    }
-
-    /**
-     * Sets a {@link PageTransformer} that will be called for each attached page whenever
-     * the scroll position is changed. This allows the application to apply custom property
-     * transformations to each page, overriding the default sliding behavior.
-     *
-     * @param reverseDrawingOrder true if the supplied PageTransformer requires page views
-     *                            to be drawn from last to first instead of first to last.
-     * @param transformer PageTransformer that will modify each page's animation properties
-     * @param pageLayerType View layer type that should be used for ViewPager pages. It should be
-     *                      either {@link View#LAYER_TYPE_HARDWARE},
-     *                      {@link View#LAYER_TYPE_SOFTWARE}, or
-     *                      {@link View#LAYER_TYPE_NONE}.
-     */
-    public void setPageTransformer(boolean reverseDrawingOrder,
-            @Nullable PageTransformer transformer, int pageLayerType) {
-        final boolean hasTransformer = transformer != null;
-        final boolean needsPopulate = hasTransformer != (mPageTransformer != null);
-        mPageTransformer = transformer;
-        setChildrenDrawingOrderEnabled(hasTransformer);
-        if (hasTransformer) {
-            mDrawingOrder = reverseDrawingOrder ? DRAW_ORDER_REVERSE : DRAW_ORDER_FORWARD;
-            mPageTransformerLayerType = pageLayerType;
-        } else {
-            mDrawingOrder = DRAW_ORDER_DEFAULT;
-        }
-        if (needsPopulate) populate();
-    }
-
-    @Override
-    protected int getChildDrawingOrder(int childCount, int i) {
-        final int index = mDrawingOrder == DRAW_ORDER_REVERSE ? childCount - 1 - i : i;
-        final int result =
-                ((LayoutParams) mDrawingOrderedChildren.get(index).getLayoutParams()).childIndex;
-        return result;
-    }
-
-    /**
-     * Set a separate OnPageChangeListener for internal use by the support library.
-     *
-     * @param listener Listener to set
-     * @return The old listener that was set, if any.
-     */
-    OnPageChangeListener setInternalPageChangeListener(OnPageChangeListener listener) {
-        OnPageChangeListener oldListener = mInternalPageChangeListener;
-        mInternalPageChangeListener = listener;
-        return oldListener;
-    }
-
-    /**
-     * Returns the number of pages that will be retained to either side of the
-     * current page in the view hierarchy in an idle state. Defaults to 1.
-     *
-     * @return How many pages will be kept offscreen on either side
-     * @see #setOffscreenPageLimit(int)
-     */
-    public int getOffscreenPageLimit() {
-        return mOffscreenPageLimit;
-    }
-
-    /**
-     * Set the number of pages that should be retained to either side of the
-     * current page in the view hierarchy in an idle state. Pages beyond this
-     * limit will be recreated from the adapter when needed.
-     *
-     * <p>This is offered as an optimization. If you know in advance the number
-     * of pages you will need to support or have lazy-loading mechanisms in place
-     * on your pages, tweaking this setting can have benefits in perceived smoothness
-     * of paging animations and interaction. If you have a small number of pages (3-4)
-     * that you can keep active all at once, less time will be spent in layout for
-     * newly created view subtrees as the user pages back and forth.</p>
-     *
-     * <p>You should keep this limit low, especially if your pages have complex layouts.
-     * This setting defaults to 1.</p>
-     *
-     * @param limit How many pages will be kept offscreen in an idle state.
-     */
-    public void setOffscreenPageLimit(int limit) {
-        if (limit < DEFAULT_OFFSCREEN_PAGES) {
-            Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to "
-                    + DEFAULT_OFFSCREEN_PAGES);
-            limit = DEFAULT_OFFSCREEN_PAGES;
-        }
-        if (limit != mOffscreenPageLimit) {
-            mOffscreenPageLimit = limit;
-            populate();
-        }
-    }
-
-    /**
-     * Set the margin between pages.
-     *
-     * @param marginPixels Distance between adjacent pages in pixels
-     * @see #getPageMargin()
-     * @see #setPageMarginDrawable(Drawable)
-     * @see #setPageMarginDrawable(int)
-     */
-    public void setPageMargin(int marginPixels) {
-        final int oldMargin = mPageMargin;
-        mPageMargin = marginPixels;
-
-        final int width = getWidth();
-        recomputeScrollPosition(width, width, marginPixels, oldMargin);
-
-        requestLayout();
-    }
-
-    /**
-     * Return the margin between pages.
-     *
-     * @return The size of the margin in pixels
-     */
-    public int getPageMargin() {
-        return mPageMargin;
-    }
-
-    /**
-     * Set a drawable that will be used to fill the margin between pages.
-     *
-     * @param d Drawable to display between pages
-     */
-    public void setPageMarginDrawable(@Nullable Drawable d) {
-        mMarginDrawable = d;
-        if (d != null) refreshDrawableState();
-        setWillNotDraw(d == null);
-        invalidate();
-    }
-
-    /**
-     * Set a drawable that will be used to fill the margin between pages.
-     *
-     * @param resId Resource ID of a drawable to display between pages
-     */
-    public void setPageMarginDrawable(@DrawableRes int resId) {
-        setPageMarginDrawable(ContextCompat.getDrawable(getContext(), resId));
-    }
-
-    @Override
-    protected boolean verifyDrawable(Drawable who) {
-        return super.verifyDrawable(who) || who == mMarginDrawable;
-    }
-
-    @Override
-    protected void drawableStateChanged() {
-        super.drawableStateChanged();
-        final Drawable d = mMarginDrawable;
-        if (d != null && d.isStateful()) {
-            d.setState(getDrawableState());
-        }
-    }
-
-    // We want the duration of the page snap animation to be influenced by the distance that
-    // the screen has to travel, however, we don't want this duration to be effected in a
-    // purely linear fashion. Instead, we use this method to moderate the effect that the distance
-    // of travel has on the overall snap duration.
-    float distanceInfluenceForSnapDuration(float f) {
-        f -= 0.5f; // center the values about 0.
-        f *= 0.3f * (float) Math.PI / 2.0f;
-        return (float) Math.sin(f);
-    }
-
-    /**
-     * Like {@link View#scrollBy}, but scroll smoothly instead of immediately.
-     *
-     * @param x the number of pixels to scroll by on the X axis
-     * @param y the number of pixels to scroll by on the Y axis
-     */
-    void smoothScrollTo(int x, int y) {
-        smoothScrollTo(x, y, 0);
-    }
-
-    /**
-     * Like {@link View#scrollBy}, but scroll smoothly instead of immediately.
-     *
-     * @param x the number of pixels to scroll by on the X axis
-     * @param y the number of pixels to scroll by on the Y axis
-     * @param velocity the velocity associated with a fling, if applicable. (0 otherwise)
-     */
-    void smoothScrollTo(int x, int y, int velocity) {
-        if (getChildCount() == 0) {
-            // Nothing to do.
-            setScrollingCacheEnabled(false);
-            return;
-        }
-
-        int sx;
-        boolean wasScrolling = (mScroller != null) && !mScroller.isFinished();
-        if (wasScrolling) {
-            // We're in the middle of a previously initiated scrolling. Check to see
-            // whether that scrolling has actually started (if we always call getStartX
-            // we can get a stale value from the scroller if it hadn't yet had its first
-            // computeScrollOffset call) to decide what is the current scrolling position.
-            sx = mIsScrollStarted ? mScroller.getCurrX() : mScroller.getStartX();
-            // And abort the current scrolling.
-            mScroller.abortAnimation();
-            setScrollingCacheEnabled(false);
-        } else {
-            sx = getScrollX();
-        }
-        int sy = getScrollY();
-        int dx = x - sx;
-        int dy = y - sy;
-        if (dx == 0 && dy == 0) {
-            completeScroll(false);
-            populate();
-            setScrollState(SCROLL_STATE_IDLE);
-            return;
-        }
-
-        setScrollingCacheEnabled(true);
-        setScrollState(SCROLL_STATE_SETTLING);
-
-        final int width = getClientWidth();
-        final int halfWidth = width / 2;
-        final float distanceRatio = Math.min(1f, 1.0f * Math.abs(dx) / width);
-        final float distance = halfWidth + halfWidth
-                * distanceInfluenceForSnapDuration(distanceRatio);
-
-        int duration;
-        velocity = Math.abs(velocity);
-        if (velocity > 0) {
-            duration = 4 * Math.round(1000 * Math.abs(distance / velocity));
-        } else {
-            final float pageWidth = width * mAdapter.getPageWidth(mCurItem);
-            final float pageDelta = (float) Math.abs(dx) / (pageWidth + mPageMargin);
-            duration = (int) ((pageDelta + 1) * 100);
-        }
-        duration = Math.min(duration, MAX_SETTLE_DURATION);
-
-        // Reset the "scroll started" flag. It will be flipped to true in all places
-        // where we call computeScrollOffset().
-        mIsScrollStarted = false;
-        mScroller.startScroll(sx, sy, dx, dy, duration);
-        ViewCompat.postInvalidateOnAnimation(this);
-    }
-
-    ItemInfo addNewItem(int position, int index) {
-        ItemInfo ii = new ItemInfo();
-        ii.position = position;
-        ii.object = mAdapter.instantiateItem(this, position);
-        ii.widthFactor = mAdapter.getPageWidth(position);
-        if (index < 0 || index >= mItems.size()) {
-            mItems.add(ii);
-        } else {
-            mItems.add(index, ii);
-        }
-        return ii;
-    }
-
-    void dataSetChanged() {
-        // This method only gets called if our observer is attached, so mAdapter is non-null.
-
-        final int adapterCount = mAdapter.getCount();
-        mExpectedAdapterCount = adapterCount;
-        boolean needPopulate = mItems.size() < mOffscreenPageLimit * 2 + 1
-                && mItems.size() < adapterCount;
-        int newCurrItem = mCurItem;
-
-        boolean isUpdating = false;
-        for (int i = 0; i < mItems.size(); i++) {
-            final ItemInfo ii = mItems.get(i);
-            final int newPos = mAdapter.getItemPosition(ii.object);
-
-            if (newPos == PagerAdapter.POSITION_UNCHANGED) {
-                continue;
-            }
-
-            if (newPos == PagerAdapter.POSITION_NONE) {
-                mItems.remove(i);
-                i--;
-
-                if (!isUpdating) {
-                    mAdapter.startUpdate(this);
-                    isUpdating = true;
-                }
-
-                mAdapter.destroyItem(this, ii.position, ii.object);
-                needPopulate = true;
-
-                if (mCurItem == ii.position) {
-                    // Keep the current item in the valid range
-                    newCurrItem = Math.max(0, Math.min(mCurItem, adapterCount - 1));
-                    needPopulate = true;
-                }
-                continue;
-            }
-
-            if (ii.position != newPos) {
-                if (ii.position == mCurItem) {
-                    // Our current item changed position. Follow it.
-                    newCurrItem = newPos;
-                }
-
-                ii.position = newPos;
-                needPopulate = true;
-            }
-        }
-
-        if (isUpdating) {
-            mAdapter.finishUpdate(this);
-        }
-
-        Collections.sort(mItems, COMPARATOR);
-
-        if (needPopulate) {
-            // Reset our known page widths; populate will recompute them.
-            final int childCount = getChildCount();
-            for (int i = 0; i < childCount; i++) {
-                final View child = getChildAt(i);
-                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-                if (!lp.isDecor) {
-                    lp.widthFactor = 0.f;
-                }
-            }
-
-            setCurrentItemInternal(newCurrItem, false, true);
-            requestLayout();
-        }
-    }
-
-    void populate() {
-        populate(mCurItem);
-    }
-
-    void populate(int newCurrentItem) {
-        ItemInfo oldCurInfo = null;
-        if (mCurItem != newCurrentItem) {
-            oldCurInfo = infoForPosition(mCurItem);
-            mCurItem = newCurrentItem;
-        }
-
-        if (mAdapter == null) {
-            sortChildDrawingOrder();
-            return;
-        }
-
-        // Bail now if we are waiting to populate.  This is to hold off
-        // on creating views from the time the user releases their finger to
-        // fling to a new position until we have finished the scroll to
-        // that position, avoiding glitches from happening at that point.
-        if (mPopulatePending) {
-            if (DEBUG) Log.i(TAG, "populate is pending, skipping for now...");
-            sortChildDrawingOrder();
-            return;
-        }
-
-        // Also, don't populate until we are attached to a window.  This is to
-        // avoid trying to populate before we have restored our view hierarchy
-        // state and conflicting with what is restored.
-        if (getWindowToken() == null) {
-            return;
-        }
-
-        mAdapter.startUpdate(this);
-
-        final int pageLimit = mOffscreenPageLimit;
-        final int startPos = Math.max(0, mCurItem - pageLimit);
-        final int N = mAdapter.getCount();
-        final int endPos = Math.min(N - 1, mCurItem + pageLimit);
-
-        if (N != mExpectedAdapterCount) {
-            String resName;
-            try {
-                resName = getResources().getResourceName(getId());
-            } catch (Resources.NotFoundException e) {
-                resName = Integer.toHexString(getId());
-            }
-            throw new IllegalStateException("The application's PagerAdapter changed the adapter's"
-                    + " contents without calling PagerAdapter#notifyDataSetChanged!"
-                    + " Expected adapter item count: " + mExpectedAdapterCount + ", found: " + N
-                    + " Pager id: " + resName
-                    + " Pager class: " + getClass()
-                    + " Problematic adapter: " + mAdapter.getClass());
-        }
-
-        // Locate the currently focused item or add it if needed.
-        int curIndex = -1;
-        ItemInfo curItem = null;
-        for (curIndex = 0; curIndex < mItems.size(); curIndex++) {
-            final ItemInfo ii = mItems.get(curIndex);
-            if (ii.position >= mCurItem) {
-                if (ii.position == mCurItem) curItem = ii;
-                break;
-            }
-        }
-
-        if (curItem == null && N > 0) {
-            curItem = addNewItem(mCurItem, curIndex);
-        }
-
-        // Fill 3x the available width or up to the number of offscreen
-        // pages requested to either side, whichever is larger.
-        // If we have no current item we have no work to do.
-        if (curItem != null) {
-            float extraWidthLeft = 0.f;
-            int itemIndex = curIndex - 1;
-            ItemInfo ii = itemIndex >= 0 ? mItems.get(itemIndex) : null;
-            final int clientWidth = getClientWidth();
-            final float leftWidthNeeded = clientWidth <= 0 ? 0 :
-                    2.f - curItem.widthFactor + (float) getPaddingLeft() / (float) clientWidth;
-            for (int pos = mCurItem - 1; pos >= 0; pos--) {
-                if (extraWidthLeft >= leftWidthNeeded && pos < startPos) {
-                    if (ii == null) {
-                        break;
-                    }
-                    if (pos == ii.position && !ii.scrolling) {
-                        mItems.remove(itemIndex);
-                        mAdapter.destroyItem(this, pos, ii.object);
-                        if (DEBUG) {
-                            Log.i(TAG, "populate() - destroyItem() with pos: " + pos
-                                    + " view: " + ((View) ii.object));
-                        }
-                        itemIndex--;
-                        curIndex--;
-                        ii = itemIndex >= 0 ? mItems.get(itemIndex) : null;
-                    }
-                } else if (ii != null && pos == ii.position) {
-                    extraWidthLeft += ii.widthFactor;
-                    itemIndex--;
-                    ii = itemIndex >= 0 ? mItems.get(itemIndex) : null;
-                } else {
-                    ii = addNewItem(pos, itemIndex + 1);
-                    extraWidthLeft += ii.widthFactor;
-                    curIndex++;
-                    ii = itemIndex >= 0 ? mItems.get(itemIndex) : null;
-                }
-            }
-
-            float extraWidthRight = curItem.widthFactor;
-            itemIndex = curIndex + 1;
-            if (extraWidthRight < 2.f) {
-                ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null;
-                final float rightWidthNeeded = clientWidth <= 0 ? 0 :
-                        (float) getPaddingRight() / (float) clientWidth + 2.f;
-                for (int pos = mCurItem + 1; pos < N; pos++) {
-                    if (extraWidthRight >= rightWidthNeeded && pos > endPos) {
-                        if (ii == null) {
-                            break;
-                        }
-                        if (pos == ii.position && !ii.scrolling) {
-                            mItems.remove(itemIndex);
-                            mAdapter.destroyItem(this, pos, ii.object);
-                            if (DEBUG) {
-                                Log.i(TAG, "populate() - destroyItem() with pos: " + pos
-                                        + " view: " + ((View) ii.object));
-                            }
-                            ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null;
-                        }
-                    } else if (ii != null && pos == ii.position) {
-                        extraWidthRight += ii.widthFactor;
-                        itemIndex++;
-                        ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null;
-                    } else {
-                        ii = addNewItem(pos, itemIndex);
-                        itemIndex++;
-                        extraWidthRight += ii.widthFactor;
-                        ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null;
-                    }
-                }
-            }
-
-            calculatePageOffsets(curItem, curIndex, oldCurInfo);
-
-            mAdapter.setPrimaryItem(this, mCurItem, curItem.object);
-        }
-
-        if (DEBUG) {
-            Log.i(TAG, "Current page list:");
-            for (int i = 0; i < mItems.size(); i++) {
-                Log.i(TAG, "#" + i + ": page " + mItems.get(i).position);
-            }
-        }
-
-        mAdapter.finishUpdate(this);
-
-        // Check width measurement of current pages and drawing sort order.
-        // Update LayoutParams as needed.
-        final int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            final View child = getChildAt(i);
-            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-            lp.childIndex = i;
-            if (!lp.isDecor && lp.widthFactor == 0.f) {
-                // 0 means requery the adapter for this, it doesn't have a valid width.
-                final ItemInfo ii = infoForChild(child);
-                if (ii != null) {
-                    lp.widthFactor = ii.widthFactor;
-                    lp.position = ii.position;
-                }
-            }
-        }
-        sortChildDrawingOrder();
-
-        if (hasFocus()) {
-            View currentFocused = findFocus();
-            ItemInfo ii = currentFocused != null ? infoForAnyChild(currentFocused) : null;
-            if (ii == null || ii.position != mCurItem) {
-                for (int i = 0; i < getChildCount(); i++) {
-                    View child = getChildAt(i);
-                    ii = infoForChild(child);
-                    if (ii != null && ii.position == mCurItem) {
-                        if (child.requestFocus(View.FOCUS_FORWARD)) {
-                            break;
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    private void sortChildDrawingOrder() {
-        if (mDrawingOrder != DRAW_ORDER_DEFAULT) {
-            if (mDrawingOrderedChildren == null) {
-                mDrawingOrderedChildren = new ArrayList<View>();
-            } else {
-                mDrawingOrderedChildren.clear();
-            }
-            final int childCount = getChildCount();
-            for (int i = 0; i < childCount; i++) {
-                final View child = getChildAt(i);
-                mDrawingOrderedChildren.add(child);
-            }
-            Collections.sort(mDrawingOrderedChildren, sPositionComparator);
-        }
-    }
-
-    private void calculatePageOffsets(ItemInfo curItem, int curIndex, ItemInfo oldCurInfo) {
-        final int N = mAdapter.getCount();
-        final int width = getClientWidth();
-        final float marginOffset = width > 0 ? (float) mPageMargin / width : 0;
-        // Fix up offsets for later layout.
-        if (oldCurInfo != null) {
-            final int oldCurPosition = oldCurInfo.position;
-            // Base offsets off of oldCurInfo.
-            if (oldCurPosition < curItem.position) {
-                int itemIndex = 0;
-                ItemInfo ii = null;
-                float offset = oldCurInfo.offset + oldCurInfo.widthFactor + marginOffset;
-                for (int pos = oldCurPosition + 1;
-                        pos <= curItem.position && itemIndex < mItems.size(); pos++) {
-                    ii = mItems.get(itemIndex);
-                    while (pos > ii.position && itemIndex < mItems.size() - 1) {
-                        itemIndex++;
-                        ii = mItems.get(itemIndex);
-                    }
-                    while (pos < ii.position) {
-                        // We don't have an item populated for this,
-                        // ask the adapter for an offset.
-                        offset += mAdapter.getPageWidth(pos) + marginOffset;
-                        pos++;
-                    }
-                    ii.offset = offset;
-                    offset += ii.widthFactor + marginOffset;
-                }
-            } else if (oldCurPosition > curItem.position) {
-                int itemIndex = mItems.size() - 1;
-                ItemInfo ii = null;
-                float offset = oldCurInfo.offset;
-                for (int pos = oldCurPosition - 1;
-                        pos >= curItem.position && itemIndex >= 0; pos--) {
-                    ii = mItems.get(itemIndex);
-                    while (pos < ii.position && itemIndex > 0) {
-                        itemIndex--;
-                        ii = mItems.get(itemIndex);
-                    }
-                    while (pos > ii.position) {
-                        // We don't have an item populated for this,
-                        // ask the adapter for an offset.
-                        offset -= mAdapter.getPageWidth(pos) + marginOffset;
-                        pos--;
-                    }
-                    offset -= ii.widthFactor + marginOffset;
-                    ii.offset = offset;
-                }
-            }
-        }
-
-        // Base all offsets off of curItem.
-        final int itemCount = mItems.size();
-        float offset = curItem.offset;
-        int pos = curItem.position - 1;
-        mFirstOffset = curItem.position == 0 ? curItem.offset : -Float.MAX_VALUE;
-        mLastOffset = curItem.position == N - 1
-                ? curItem.offset + curItem.widthFactor - 1 : Float.MAX_VALUE;
-        // Previous pages
-        for (int i = curIndex - 1; i >= 0; i--, pos--) {
-            final ItemInfo ii = mItems.get(i);
-            while (pos > ii.position) {
-                offset -= mAdapter.getPageWidth(pos--) + marginOffset;
-            }
-            offset -= ii.widthFactor + marginOffset;
-            ii.offset = offset;
-            if (ii.position == 0) mFirstOffset = offset;
-        }
-        offset = curItem.offset + curItem.widthFactor + marginOffset;
-        pos = curItem.position + 1;
-        // Next pages
-        for (int i = curIndex + 1; i < itemCount; i++, pos++) {
-            final ItemInfo ii = mItems.get(i);
-            while (pos < ii.position) {
-                offset += mAdapter.getPageWidth(pos++) + marginOffset;
-            }
-            if (ii.position == N - 1) {
-                mLastOffset = offset + ii.widthFactor - 1;
-            }
-            ii.offset = offset;
-            offset += ii.widthFactor + marginOffset;
-        }
-
-        mNeedCalculatePageOffsets = false;
-    }
-
-    /**
-     * This is the persistent state that is saved by ViewPager.  Only needed
-     * if you are creating a sublass of ViewPager that must save its own
-     * state, in which case it should implement a subclass of this which
-     * contains that state.
-     */
-    public static class SavedState extends AbsSavedState {
-        int position;
-        Parcelable adapterState;
-        ClassLoader loader;
-
-        public SavedState(@NonNull Parcelable superState) {
-            super(superState);
-        }
-
-        @Override
-        public void writeToParcel(Parcel out, int flags) {
-            super.writeToParcel(out, flags);
-            out.writeInt(position);
-            out.writeParcelable(adapterState, flags);
-        }
-
-        @Override
-        public String toString() {
-            return "FragmentPager.SavedState{"
-                    + Integer.toHexString(System.identityHashCode(this))
-                    + " position=" + position + "}";
-        }
-
-        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];
-            }
-        };
-
-        SavedState(Parcel in, ClassLoader loader) {
-            super(in, loader);
-            if (loader == null) {
-                loader = getClass().getClassLoader();
-            }
-            position = in.readInt();
-            adapterState = in.readParcelable(loader);
-            this.loader = loader;
-        }
-    }
-
-    @Override
-    public Parcelable onSaveInstanceState() {
-        Parcelable superState = super.onSaveInstanceState();
-        SavedState ss = new SavedState(superState);
-        ss.position = mCurItem;
-        if (mAdapter != null) {
-            ss.adapterState = mAdapter.saveState();
-        }
-        return ss;
-    }
-
-    @Override
-    public void onRestoreInstanceState(Parcelable state) {
-        if (!(state instanceof SavedState)) {
-            super.onRestoreInstanceState(state);
-            return;
-        }
-
-        SavedState ss = (SavedState) state;
-        super.onRestoreInstanceState(ss.getSuperState());
-
-        if (mAdapter != null) {
-            mAdapter.restoreState(ss.adapterState, ss.loader);
-            setCurrentItemInternal(ss.position, false, true);
-        } else {
-            mRestoredCurItem = ss.position;
-            mRestoredAdapterState = ss.adapterState;
-            mRestoredClassLoader = ss.loader;
-        }
-    }
-
-    @Override
-    public void addView(View child, int index, ViewGroup.LayoutParams params) {
-        if (!checkLayoutParams(params)) {
-            params = generateLayoutParams(params);
-        }
-        final LayoutParams lp = (LayoutParams) params;
-        // Any views added via inflation should be classed as part of the decor
-        lp.isDecor |= isDecorView(child);
-        if (mInLayout) {
-            if (lp != null && lp.isDecor) {
-                throw new IllegalStateException("Cannot add pager decor view during layout");
-            }
-            lp.needsMeasure = true;
-            addViewInLayout(child, index, params);
-        } else {
-            super.addView(child, index, params);
-        }
-
-        if (USE_CACHE) {
-            if (child.getVisibility() != GONE) {
-                child.setDrawingCacheEnabled(mScrollingCacheEnabled);
-            } else {
-                child.setDrawingCacheEnabled(false);
-            }
-        }
-    }
-
-    private static boolean isDecorView(@NonNull View view) {
-        Class<?> clazz = view.getClass();
-        return clazz.getAnnotation(DecorView.class) != null;
-    }
-
-    @Override
-    public void removeView(View view) {
-        if (mInLayout) {
-            removeViewInLayout(view);
-        } else {
-            super.removeView(view);
-        }
-    }
-
-    ItemInfo infoForChild(View child) {
-        for (int i = 0; i < mItems.size(); i++) {
-            ItemInfo ii = mItems.get(i);
-            if (mAdapter.isViewFromObject(child, ii.object)) {
-                return ii;
-            }
-        }
-        return null;
-    }
-
-    ItemInfo infoForAnyChild(View child) {
-        ViewParent parent;
-        while ((parent = child.getParent()) != this) {
-            if (parent == null || !(parent instanceof View)) {
-                return null;
-            }
-            child = (View) parent;
-        }
-        return infoForChild(child);
-    }
-
-    ItemInfo infoForPosition(int position) {
-        for (int i = 0; i < mItems.size(); i++) {
-            ItemInfo ii = mItems.get(i);
-            if (ii.position == position) {
-                return ii;
-            }
-        }
-        return null;
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        mFirstLayout = true;
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        // For simple implementation, our internal size is always 0.
-        // We depend on the container to specify the layout size of
-        // our view.  We can't really know what it is since we will be
-        // adding and removing different arbitrary views and do not
-        // want the layout to change as this happens.
-        setMeasuredDimension(getDefaultSize(0, widthMeasureSpec),
-                getDefaultSize(0, heightMeasureSpec));
-
-        final int measuredWidth = getMeasuredWidth();
-        final int maxGutterSize = measuredWidth / 10;
-        mGutterSize = Math.min(maxGutterSize, mDefaultGutterSize);
-
-        // Children are just made to fill our space.
-        int childWidthSize = measuredWidth - getPaddingLeft() - getPaddingRight();
-        int childHeightSize = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
-
-        /*
-         * Make sure all children have been properly measured. Decor views first.
-         * Right now we cheat and make this less complicated by assuming decor
-         * views won't intersect. We will pin to edges based on gravity.
-         */
-        int size = getChildCount();
-        for (int i = 0; i < size; ++i) {
-            final View child = getChildAt(i);
-            if (child.getVisibility() != GONE) {
-                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-                if (lp != null && lp.isDecor) {
-                    final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
-                    final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK;
-                    int widthMode = MeasureSpec.AT_MOST;
-                    int heightMode = MeasureSpec.AT_MOST;
-                    boolean consumeVertical = vgrav == Gravity.TOP || vgrav == Gravity.BOTTOM;
-                    boolean consumeHorizontal = hgrav == Gravity.LEFT || hgrav == Gravity.RIGHT;
-
-                    if (consumeVertical) {
-                        widthMode = MeasureSpec.EXACTLY;
-                    } else if (consumeHorizontal) {
-                        heightMode = MeasureSpec.EXACTLY;
-                    }
-
-                    int widthSize = childWidthSize;
-                    int heightSize = childHeightSize;
-                    if (lp.width != LayoutParams.WRAP_CONTENT) {
-                        widthMode = MeasureSpec.EXACTLY;
-                        if (lp.width != LayoutParams.MATCH_PARENT) {
-                            widthSize = lp.width;
-                        }
-                    }
-                    if (lp.height != LayoutParams.WRAP_CONTENT) {
-                        heightMode = MeasureSpec.EXACTLY;
-                        if (lp.height != LayoutParams.MATCH_PARENT) {
-                            heightSize = lp.height;
-                        }
-                    }
-                    final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, widthMode);
-                    final int heightSpec = MeasureSpec.makeMeasureSpec(heightSize, heightMode);
-                    child.measure(widthSpec, heightSpec);
-
-                    if (consumeVertical) {
-                        childHeightSize -= child.getMeasuredHeight();
-                    } else if (consumeHorizontal) {
-                        childWidthSize -= child.getMeasuredWidth();
-                    }
-                }
-            }
-        }
-
-        mChildWidthMeasureSpec = MeasureSpec.makeMeasureSpec(childWidthSize, MeasureSpec.EXACTLY);
-        mChildHeightMeasureSpec = MeasureSpec.makeMeasureSpec(childHeightSize, MeasureSpec.EXACTLY);
-
-        // Make sure we have created all fragments that we need to have shown.
-        mInLayout = true;
-        populate();
-        mInLayout = false;
-
-        // Page views next.
-        size = getChildCount();
-        for (int i = 0; i < size; ++i) {
-            final View child = getChildAt(i);
-            if (child.getVisibility() != GONE) {
-                if (DEBUG) {
-                    Log.v(TAG, "Measuring #" + i + " " + child + ": " + mChildWidthMeasureSpec);
-                }
-
-                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-                if (lp == null || !lp.isDecor) {
-                    final int widthSpec = MeasureSpec.makeMeasureSpec(
-                            (int) (childWidthSize * lp.widthFactor), MeasureSpec.EXACTLY);
-                    child.measure(widthSpec, mChildHeightMeasureSpec);
-                }
-            }
-        }
-    }
-
-    @Override
-    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-        super.onSizeChanged(w, h, oldw, oldh);
-
-        // Make sure scroll position is set correctly.
-        if (w != oldw) {
-            recomputeScrollPosition(w, oldw, mPageMargin, mPageMargin);
-        }
-    }
-
-    private void recomputeScrollPosition(int width, int oldWidth, int margin, int oldMargin) {
-        if (oldWidth > 0 && !mItems.isEmpty()) {
-            if (!mScroller.isFinished()) {
-                mScroller.setFinalX(getCurrentItem() * getClientWidth());
-            } else {
-                final int widthWithMargin = width - getPaddingLeft() - getPaddingRight() + margin;
-                final int oldWidthWithMargin = oldWidth - getPaddingLeft() - getPaddingRight()
-                        + oldMargin;
-                final int xpos = getScrollX();
-                final float pageOffset = (float) xpos / oldWidthWithMargin;
-                final int newOffsetPixels = (int) (pageOffset * widthWithMargin);
-
-                scrollTo(newOffsetPixels, getScrollY());
-            }
-        } else {
-            final ItemInfo ii = infoForPosition(mCurItem);
-            final float scrollOffset = ii != null ? Math.min(ii.offset, mLastOffset) : 0;
-            final int scrollPos =
-                    (int) (scrollOffset * (width - getPaddingLeft() - getPaddingRight()));
-            if (scrollPos != getScrollX()) {
-                completeScroll(false);
-                scrollTo(scrollPos, getScrollY());
-            }
-        }
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int l, int t, int r, int b) {
-        final int count = getChildCount();
-        int width = r - l;
-        int height = b - t;
-        int paddingLeft = getPaddingLeft();
-        int paddingTop = getPaddingTop();
-        int paddingRight = getPaddingRight();
-        int paddingBottom = getPaddingBottom();
-        final int scrollX = getScrollX();
-
-        int decorCount = 0;
-
-        // First pass - decor views. We need to do this in two passes so that
-        // we have the proper offsets for non-decor views later.
-        for (int i = 0; i < count; i++) {
-            final View child = getChildAt(i);
-            if (child.getVisibility() != GONE) {
-                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-                int childLeft = 0;
-                int childTop = 0;
-                if (lp.isDecor) {
-                    final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
-                    final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK;
-                    switch (hgrav) {
-                        default:
-                            childLeft = paddingLeft;
-                            break;
-                        case Gravity.LEFT:
-                            childLeft = paddingLeft;
-                            paddingLeft += child.getMeasuredWidth();
-                            break;
-                        case Gravity.CENTER_HORIZONTAL:
-                            childLeft = Math.max((width - child.getMeasuredWidth()) / 2,
-                                    paddingLeft);
-                            break;
-                        case Gravity.RIGHT:
-                            childLeft = width - paddingRight - child.getMeasuredWidth();
-                            paddingRight += child.getMeasuredWidth();
-                            break;
-                    }
-                    switch (vgrav) {
-                        default:
-                            childTop = paddingTop;
-                            break;
-                        case Gravity.TOP:
-                            childTop = paddingTop;
-                            paddingTop += child.getMeasuredHeight();
-                            break;
-                        case Gravity.CENTER_VERTICAL:
-                            childTop = Math.max((height - child.getMeasuredHeight()) / 2,
-                                    paddingTop);
-                            break;
-                        case Gravity.BOTTOM:
-                            childTop = height - paddingBottom - child.getMeasuredHeight();
-                            paddingBottom += child.getMeasuredHeight();
-                            break;
-                    }
-                    childLeft += scrollX;
-                    child.layout(childLeft, childTop,
-                            childLeft + child.getMeasuredWidth(),
-                            childTop + child.getMeasuredHeight());
-                    decorCount++;
-                }
-            }
-        }
-
-        final int childWidth = width - paddingLeft - paddingRight;
-        // Page views. Do this once we have the right padding offsets from above.
-        for (int i = 0; i < count; i++) {
-            final View child = getChildAt(i);
-            if (child.getVisibility() != GONE) {
-                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-                ItemInfo ii;
-                if (!lp.isDecor && (ii = infoForChild(child)) != null) {
-                    int loff = (int) (childWidth * ii.offset);
-                    int childLeft = paddingLeft + loff;
-                    int childTop = paddingTop;
-                    if (lp.needsMeasure) {
-                        // This was added during layout and needs measurement.
-                        // Do it now that we know what we're working with.
-                        lp.needsMeasure = false;
-                        final int widthSpec = MeasureSpec.makeMeasureSpec(
-                                (int) (childWidth * lp.widthFactor),
-                                MeasureSpec.EXACTLY);
-                        final int heightSpec = MeasureSpec.makeMeasureSpec(
-                                (int) (height - paddingTop - paddingBottom),
-                                MeasureSpec.EXACTLY);
-                        child.measure(widthSpec, heightSpec);
-                    }
-                    if (DEBUG) {
-                        Log.v(TAG, "Positioning #" + i + " " + child + " f=" + ii.object
-                                + ":" + childLeft + "," + childTop + " " + child.getMeasuredWidth()
-                                + "x" + child.getMeasuredHeight());
-                    }
-                    child.layout(childLeft, childTop,
-                            childLeft + child.getMeasuredWidth(),
-                            childTop + child.getMeasuredHeight());
-                }
-            }
-        }
-        mTopPageBounds = paddingTop;
-        mBottomPageBounds = height - paddingBottom;
-        mDecorChildCount = decorCount;
-
-        if (mFirstLayout) {
-            scrollToItem(mCurItem, false, 0, false);
-        }
-        mFirstLayout = false;
-    }
-
-    @Override
-    public void computeScroll() {
-        mIsScrollStarted = true;
-        if (!mScroller.isFinished() && mScroller.computeScrollOffset()) {
-            int oldX = getScrollX();
-            int oldY = getScrollY();
-            int x = mScroller.getCurrX();
-            int y = mScroller.getCurrY();
-
-            if (oldX != x || oldY != y) {
-                scrollTo(x, y);
-                if (!pageScrolled(x)) {
-                    mScroller.abortAnimation();
-                    scrollTo(0, y);
-                }
-            }
-
-            // Keep on drawing until the animation has finished.
-            ViewCompat.postInvalidateOnAnimation(this);
-            return;
-        }
-
-        // Done with scroll, clean up state.
-        completeScroll(true);
-    }
-
-    private boolean pageScrolled(int xpos) {
-        if (mItems.size() == 0) {
-            if (mFirstLayout) {
-                // If we haven't been laid out yet, we probably just haven't been populated yet.
-                // Let's skip this call since it doesn't make sense in this state
-                return false;
-            }
-            mCalledSuper = false;
-            onPageScrolled(0, 0, 0);
-            if (!mCalledSuper) {
-                throw new IllegalStateException(
-                        "onPageScrolled did not call superclass implementation");
-            }
-            return false;
-        }
-        final ItemInfo ii = infoForCurrentScrollPosition();
-        final int width = getClientWidth();
-        final int widthWithMargin = width + mPageMargin;
-        final float marginOffset = (float) mPageMargin / width;
-        final int currentPage = ii.position;
-        final float pageOffset = (((float) xpos / width) - ii.offset)
-                / (ii.widthFactor + marginOffset);
-        final int offsetPixels = (int) (pageOffset * widthWithMargin);
-
-        mCalledSuper = false;
-        onPageScrolled(currentPage, pageOffset, offsetPixels);
-        if (!mCalledSuper) {
-            throw new IllegalStateException(
-                    "onPageScrolled did not call superclass implementation");
-        }
-        return true;
-    }
-
-    /**
-     * This method will be invoked when the current page is scrolled, either as part
-     * of a programmatically initiated smooth scroll or a user initiated touch scroll.
-     * If you override this method you must call through to the superclass implementation
-     * (e.g. super.onPageScrolled(position, offset, offsetPixels)) before onPageScrolled
-     * returns.
-     *
-     * @param position Position index of the first page currently being displayed.
-     *                 Page position+1 will be visible if positionOffset is nonzero.
-     * @param offset Value from [0, 1) indicating the offset from the page at position.
-     * @param offsetPixels Value in pixels indicating the offset from position.
-     */
-    @CallSuper
-    protected void onPageScrolled(int position, float offset, int offsetPixels) {
-        // Offset any decor views if needed - keep them on-screen at all times.
-        if (mDecorChildCount > 0) {
-            final int scrollX = getScrollX();
-            int paddingLeft = getPaddingLeft();
-            int paddingRight = getPaddingRight();
-            final int width = getWidth();
-            final int childCount = getChildCount();
-            for (int i = 0; i < childCount; i++) {
-                final View child = getChildAt(i);
-                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-                if (!lp.isDecor) continue;
-
-                final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
-                int childLeft = 0;
-                switch (hgrav) {
-                    default:
-                        childLeft = paddingLeft;
-                        break;
-                    case Gravity.LEFT:
-                        childLeft = paddingLeft;
-                        paddingLeft += child.getWidth();
-                        break;
-                    case Gravity.CENTER_HORIZONTAL:
-                        childLeft = Math.max((width - child.getMeasuredWidth()) / 2,
-                                paddingLeft);
-                        break;
-                    case Gravity.RIGHT:
-                        childLeft = width - paddingRight - child.getMeasuredWidth();
-                        paddingRight += child.getMeasuredWidth();
-                        break;
-                }
-                childLeft += scrollX;
-
-                final int childOffset = childLeft - child.getLeft();
-                if (childOffset != 0) {
-                    child.offsetLeftAndRight(childOffset);
-                }
-            }
-        }
-
-        dispatchOnPageScrolled(position, offset, offsetPixels);
-
-        if (mPageTransformer != null) {
-            final int scrollX = getScrollX();
-            final int childCount = getChildCount();
-            for (int i = 0; i < childCount; i++) {
-                final View child = getChildAt(i);
-                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-
-                if (lp.isDecor) continue;
-                final float transformPos = (float) (child.getLeft() - scrollX) / getClientWidth();
-                mPageTransformer.transformPage(child, transformPos);
-            }
-        }
-
-        mCalledSuper = true;
-    }
-
-    private void dispatchOnPageScrolled(int position, float offset, int offsetPixels) {
-        if (mOnPageChangeListener != null) {
-            mOnPageChangeListener.onPageScrolled(position, offset, offsetPixels);
-        }
-        if (mOnPageChangeListeners != null) {
-            for (int i = 0, z = mOnPageChangeListeners.size(); i < z; i++) {
-                OnPageChangeListener listener = mOnPageChangeListeners.get(i);
-                if (listener != null) {
-                    listener.onPageScrolled(position, offset, offsetPixels);
-                }
-            }
-        }
-        if (mInternalPageChangeListener != null) {
-            mInternalPageChangeListener.onPageScrolled(position, offset, offsetPixels);
-        }
-    }
-
-    private void dispatchOnPageSelected(int position) {
-        if (mOnPageChangeListener != null) {
-            mOnPageChangeListener.onPageSelected(position);
-        }
-        if (mOnPageChangeListeners != null) {
-            for (int i = 0, z = mOnPageChangeListeners.size(); i < z; i++) {
-                OnPageChangeListener listener = mOnPageChangeListeners.get(i);
-                if (listener != null) {
-                    listener.onPageSelected(position);
-                }
-            }
-        }
-        if (mInternalPageChangeListener != null) {
-            mInternalPageChangeListener.onPageSelected(position);
-        }
-    }
-
-    private void dispatchOnScrollStateChanged(int state) {
-        if (mOnPageChangeListener != null) {
-            mOnPageChangeListener.onPageScrollStateChanged(state);
-        }
-        if (mOnPageChangeListeners != null) {
-            for (int i = 0, z = mOnPageChangeListeners.size(); i < z; i++) {
-                OnPageChangeListener listener = mOnPageChangeListeners.get(i);
-                if (listener != null) {
-                    listener.onPageScrollStateChanged(state);
-                }
-            }
-        }
-        if (mInternalPageChangeListener != null) {
-            mInternalPageChangeListener.onPageScrollStateChanged(state);
-        }
-    }
-
-    private void completeScroll(boolean postEvents) {
-        boolean needPopulate = mScrollState == SCROLL_STATE_SETTLING;
-        if (needPopulate) {
-            // Done with scroll, no longer want to cache view drawing.
-            setScrollingCacheEnabled(false);
-            boolean wasScrolling = !mScroller.isFinished();
-            if (wasScrolling) {
-                mScroller.abortAnimation();
-                int oldX = getScrollX();
-                int oldY = getScrollY();
-                int x = mScroller.getCurrX();
-                int y = mScroller.getCurrY();
-                if (oldX != x || oldY != y) {
-                    scrollTo(x, y);
-                    if (x != oldX) {
-                        pageScrolled(x);
-                    }
-                }
-            }
-        }
-        mPopulatePending = false;
-        for (int i = 0; i < mItems.size(); i++) {
-            ItemInfo ii = mItems.get(i);
-            if (ii.scrolling) {
-                needPopulate = true;
-                ii.scrolling = false;
-            }
-        }
-        if (needPopulate) {
-            if (postEvents) {
-                ViewCompat.postOnAnimation(this, mEndScrollRunnable);
-            } else {
-                mEndScrollRunnable.run();
-            }
-        }
-    }
-
-    private boolean isGutterDrag(float x, float dx) {
-        return (x < mGutterSize && dx > 0) || (x > getWidth() - mGutterSize && dx < 0);
-    }
-
-    private void enableLayers(boolean enable) {
-        final int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            final int layerType = enable
-                    ? mPageTransformerLayerType : View.LAYER_TYPE_NONE;
-            getChildAt(i).setLayerType(layerType, null);
-        }
-    }
-
-    @Override
-    public boolean onInterceptTouchEvent(MotionEvent ev) {
-        /*
-         * This method JUST determines whether we want to intercept the motion.
-         * If we return true, onMotionEvent will be called and we do the actual
-         * scrolling there.
-         */
-
-        final int action = ev.getAction() & MotionEvent.ACTION_MASK;
-
-        // Always take care of the touch gesture being complete.
-        if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
-            // Release the drag.
-            if (DEBUG) Log.v(TAG, "Intercept done!");
-            resetTouch();
-            return false;
-        }
-
-        // Nothing more to do here if we have decided whether or not we
-        // are dragging.
-        if (action != MotionEvent.ACTION_DOWN) {
-            if (mIsBeingDragged) {
-                if (DEBUG) Log.v(TAG, "Intercept returning true!");
-                return true;
-            }
-            if (mIsUnableToDrag) {
-                if (DEBUG) Log.v(TAG, "Intercept returning false!");
-                return false;
-            }
-        }
-
-        switch (action) {
-            case MotionEvent.ACTION_MOVE: {
-                /*
-                 * mIsBeingDragged == false, otherwise the shortcut would have caught it. Check
-                 * whether the user has moved far enough from his original down touch.
-                 */
-
-                /*
-                * Locally do absolute value. mLastMotionY is set to the y value
-                * of the down event.
-                */
-                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);
-                final float x = ev.getX(pointerIndex);
-                final float dx = x - mLastMotionX;
-                final float xDiff = Math.abs(dx);
-                final float y = ev.getY(pointerIndex);
-                final float yDiff = Math.abs(y - mInitialMotionY);
-                if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff);
-
-                if (dx != 0 && !isGutterDrag(mLastMotionX, dx)
-                        && canScroll(this, false, (int) dx, (int) x, (int) y)) {
-                    // Nested view has scrollable area under this point. Let it be handled there.
-                    mLastMotionX = x;
-                    mLastMotionY = y;
-                    mIsUnableToDrag = true;
-                    return false;
-                }
-                if (xDiff > mTouchSlop && xDiff * 0.5f > yDiff) {
-                    if (DEBUG) Log.v(TAG, "Starting drag!");
-                    mIsBeingDragged = true;
-                    requestParentDisallowInterceptTouchEvent(true);
-                    setScrollState(SCROLL_STATE_DRAGGING);
-                    mLastMotionX = dx > 0
-                            ? mInitialMotionX + mTouchSlop : mInitialMotionX - mTouchSlop;
-                    mLastMotionY = y;
-                    setScrollingCacheEnabled(true);
-                } else if (yDiff > mTouchSlop) {
-                    // The finger has moved enough in the vertical
-                    // direction to be counted as a drag...  abort
-                    // any attempt to drag horizontally, to work correctly
-                    // with children that have scrolling containers.
-                    if (DEBUG) Log.v(TAG, "Starting unable to drag!");
-                    mIsUnableToDrag = true;
-                }
-                if (mIsBeingDragged) {
-                    // Scroll to follow the motion event
-                    if (performDrag(x)) {
-                        ViewCompat.postInvalidateOnAnimation(this);
-                    }
-                }
-                break;
-            }
-
-            case MotionEvent.ACTION_DOWN: {
-                /*
-                 * Remember location of down touch.
-                 * ACTION_DOWN always refers to pointer index 0.
-                 */
-                mLastMotionX = mInitialMotionX = ev.getX();
-                mLastMotionY = mInitialMotionY = ev.getY();
-                mActivePointerId = ev.getPointerId(0);
-                mIsUnableToDrag = false;
-
-                mIsScrollStarted = true;
-                mScroller.computeScrollOffset();
-                if (mScrollState == SCROLL_STATE_SETTLING
-                        && Math.abs(mScroller.getFinalX() - mScroller.getCurrX()) > mCloseEnough) {
-                    // Let the user 'catch' the pager as it animates.
-                    mScroller.abortAnimation();
-                    mPopulatePending = false;
-                    populate();
-                    mIsBeingDragged = true;
-                    requestParentDisallowInterceptTouchEvent(true);
-                    setScrollState(SCROLL_STATE_DRAGGING);
-                } else {
-                    completeScroll(false);
-                    mIsBeingDragged = false;
-                }
-
-                if (DEBUG) {
-                    Log.v(TAG, "Down at " + mLastMotionX + "," + mLastMotionY
-                            + " mIsBeingDragged=" + mIsBeingDragged
-                            + "mIsUnableToDrag=" + mIsUnableToDrag);
-                }
-                break;
-            }
-
-            case MotionEvent.ACTION_POINTER_UP:
-                onSecondaryPointerUp(ev);
-                break;
-        }
-
-        if (mVelocityTracker == null) {
-            mVelocityTracker = VelocityTracker.obtain();
-        }
-        mVelocityTracker.addMovement(ev);
-
-        /*
-         * The only time we want to intercept motion events is if we are in the
-         * drag mode.
-         */
-        return mIsBeingDragged;
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev) {
-        if (mFakeDragging) {
-            // A fake drag is in progress already, ignore this real one
-            // but still eat the touch events.
-            // (It is likely that the user is multi-touching the screen.)
-            return true;
-        }
-
-        if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) {
-            // Don't handle edge touches immediately -- they may actually belong to one of our
-            // descendants.
-            return false;
-        }
-
-        if (mAdapter == null || mAdapter.getCount() == 0) {
-            // Nothing to present or scroll; nothing to touch.
-            return false;
-        }
-
-        if (mVelocityTracker == null) {
-            mVelocityTracker = VelocityTracker.obtain();
-        }
-        mVelocityTracker.addMovement(ev);
-
-        final int action = ev.getAction();
-        boolean needsInvalidate = false;
-
-        switch (action & MotionEvent.ACTION_MASK) {
-            case MotionEvent.ACTION_DOWN: {
-                mScroller.abortAnimation();
-                mPopulatePending = false;
-                populate();
-
-                // Remember where the motion event started
-                mLastMotionX = mInitialMotionX = ev.getX();
-                mLastMotionY = mInitialMotionY = ev.getY();
-                mActivePointerId = ev.getPointerId(0);
-                break;
-            }
-            case MotionEvent.ACTION_MOVE:
-                if (!mIsBeingDragged) {
-                    final int pointerIndex = ev.findPointerIndex(mActivePointerId);
-                    if (pointerIndex == -1) {
-                        // A child has consumed some touch events and put us into an inconsistent
-                        // state.
-                        needsInvalidate = resetTouch();
-                        break;
-                    }
-                    final float x = ev.getX(pointerIndex);
-                    final float xDiff = Math.abs(x - mLastMotionX);
-                    final float y = ev.getY(pointerIndex);
-                    final float yDiff = Math.abs(y - mLastMotionY);
-                    if (DEBUG) {
-                        Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff);
-                    }
-                    if (xDiff > mTouchSlop && xDiff > yDiff) {
-                        if (DEBUG) Log.v(TAG, "Starting drag!");
-                        mIsBeingDragged = true;
-                        requestParentDisallowInterceptTouchEvent(true);
-                        mLastMotionX = x - mInitialMotionX > 0 ? mInitialMotionX + mTouchSlop :
-                                mInitialMotionX - mTouchSlop;
-                        mLastMotionY = y;
-                        setScrollState(SCROLL_STATE_DRAGGING);
-                        setScrollingCacheEnabled(true);
-
-                        // Disallow Parent Intercept, just in case
-                        ViewParent parent = getParent();
-                        if (parent != null) {
-                            parent.requestDisallowInterceptTouchEvent(true);
-                        }
-                    }
-                }
-                // Not else! Note that mIsBeingDragged can be set above.
-                if (mIsBeingDragged) {
-                    // Scroll to follow the motion event
-                    final int activePointerIndex = ev.findPointerIndex(mActivePointerId);
-                    final float x = ev.getX(activePointerIndex);
-                    needsInvalidate |= performDrag(x);
-                }
-                break;
-            case MotionEvent.ACTION_UP:
-                if (mIsBeingDragged) {
-                    final VelocityTracker velocityTracker = mVelocityTracker;
-                    velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
-                    int initialVelocity = (int) velocityTracker.getXVelocity(mActivePointerId);
-                    mPopulatePending = true;
-                    final int width = getClientWidth();
-                    final int scrollX = getScrollX();
-                    final ItemInfo ii = infoForCurrentScrollPosition();
-                    final float marginOffset = (float) mPageMargin / width;
-                    final int currentPage = ii.position;
-                    final float pageOffset = (((float) scrollX / width) - ii.offset)
-                            / (ii.widthFactor + marginOffset);
-                    final int activePointerIndex = ev.findPointerIndex(mActivePointerId);
-                    final float x = ev.getX(activePointerIndex);
-                    final int totalDelta = (int) (x - mInitialMotionX);
-                    int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity,
-                            totalDelta);
-                    setCurrentItemInternal(nextPage, true, true, initialVelocity);
-
-                    needsInvalidate = resetTouch();
-                }
-                break;
-            case MotionEvent.ACTION_CANCEL:
-                if (mIsBeingDragged) {
-                    scrollToItem(mCurItem, true, 0, false);
-                    needsInvalidate = resetTouch();
-                }
-                break;
-            case MotionEvent.ACTION_POINTER_DOWN: {
-                final int index = ev.getActionIndex();
-                final float x = ev.getX(index);
-                mLastMotionX = x;
-                mActivePointerId = ev.getPointerId(index);
-                break;
-            }
-            case MotionEvent.ACTION_POINTER_UP:
-                onSecondaryPointerUp(ev);
-                mLastMotionX = ev.getX(ev.findPointerIndex(mActivePointerId));
-                break;
-        }
-        if (needsInvalidate) {
-            ViewCompat.postInvalidateOnAnimation(this);
-        }
-        return true;
-    }
-
-    private boolean resetTouch() {
-        boolean needsInvalidate;
-        mActivePointerId = INVALID_POINTER;
-        endDrag();
-        mLeftEdge.onRelease();
-        mRightEdge.onRelease();
-        needsInvalidate = mLeftEdge.isFinished() || mRightEdge.isFinished();
-        return needsInvalidate;
-    }
-
-    private void requestParentDisallowInterceptTouchEvent(boolean disallowIntercept) {
-        final ViewParent parent = getParent();
-        if (parent != null) {
-            parent.requestDisallowInterceptTouchEvent(disallowIntercept);
-        }
-    }
-
-    private boolean performDrag(float x) {
-        boolean needsInvalidate = false;
-
-        final float deltaX = mLastMotionX - x;
-        mLastMotionX = x;
-
-        float oldScrollX = getScrollX();
-        float scrollX = oldScrollX + deltaX;
-        final int width = getClientWidth();
-
-        float leftBound = width * mFirstOffset;
-        float rightBound = width * mLastOffset;
-        boolean leftAbsolute = true;
-        boolean rightAbsolute = true;
-
-        final ItemInfo firstItem = mItems.get(0);
-        final ItemInfo lastItem = mItems.get(mItems.size() - 1);
-        if (firstItem.position != 0) {
-            leftAbsolute = false;
-            leftBound = firstItem.offset * width;
-        }
-        if (lastItem.position != mAdapter.getCount() - 1) {
-            rightAbsolute = false;
-            rightBound = lastItem.offset * width;
-        }
-
-        if (scrollX < leftBound) {
-            if (leftAbsolute) {
-                float over = leftBound - scrollX;
-                mLeftEdge.onPull(Math.abs(over) / width);
-                needsInvalidate = true;
-            }
-            scrollX = leftBound;
-        } else if (scrollX > rightBound) {
-            if (rightAbsolute) {
-                float over = scrollX - rightBound;
-                mRightEdge.onPull(Math.abs(over) / width);
-                needsInvalidate = true;
-            }
-            scrollX = rightBound;
-        }
-        // Don't lose the rounded component
-        mLastMotionX += scrollX - (int) scrollX;
-        scrollTo((int) scrollX, getScrollY());
-        pageScrolled((int) scrollX);
-
-        return needsInvalidate;
-    }
-
-    /**
-     * @return Info about the page at the current scroll position.
-     *         This can be synthetic for a missing middle page; the 'object' field can be null.
-     */
-    private ItemInfo infoForCurrentScrollPosition() {
-        final int width = getClientWidth();
-        final float scrollOffset = width > 0 ? (float) getScrollX() / width : 0;
-        final float marginOffset = width > 0 ? (float) mPageMargin / width : 0;
-        int lastPos = -1;
-        float lastOffset = 0.f;
-        float lastWidth = 0.f;
-        boolean first = true;
-
-        ItemInfo lastItem = null;
-        for (int i = 0; i < mItems.size(); i++) {
-            ItemInfo ii = mItems.get(i);
-            float offset;
-            if (!first && ii.position != lastPos + 1) {
-                // Create a synthetic item for a missing page.
-                ii = mTempItem;
-                ii.offset = lastOffset + lastWidth + marginOffset;
-                ii.position = lastPos + 1;
-                ii.widthFactor = mAdapter.getPageWidth(ii.position);
-                i--;
-            }
-            offset = ii.offset;
-
-            final float leftBound = offset;
-            final float rightBound = offset + ii.widthFactor + marginOffset;
-            if (first || scrollOffset >= leftBound) {
-                if (scrollOffset < rightBound || i == mItems.size() - 1) {
-                    return ii;
-                }
-            } else {
-                return lastItem;
-            }
-            first = false;
-            lastPos = ii.position;
-            lastOffset = offset;
-            lastWidth = ii.widthFactor;
-            lastItem = ii;
-        }
-
-        return lastItem;
-    }
-
-    private int determineTargetPage(int currentPage, float pageOffset, int velocity, int deltaX) {
-        int targetPage;
-        if (Math.abs(deltaX) > mFlingDistance && Math.abs(velocity) > mMinimumVelocity) {
-            targetPage = velocity > 0 ? currentPage : currentPage + 1;
-        } else {
-            final float truncator = currentPage >= mCurItem ? 0.4f : 0.6f;
-            targetPage = currentPage + (int) (pageOffset + truncator);
-        }
-
-        if (mItems.size() > 0) {
-            final ItemInfo firstItem = mItems.get(0);
-            final ItemInfo lastItem = mItems.get(mItems.size() - 1);
-
-            // Only let the user target pages we have items for
-            targetPage = Math.max(firstItem.position, Math.min(targetPage, lastItem.position));
-        }
-
-        return targetPage;
-    }
-
-    @Override
-    public void draw(Canvas canvas) {
-        super.draw(canvas);
-        boolean needsInvalidate = false;
-
-        final int overScrollMode = getOverScrollMode();
-        if (overScrollMode == View.OVER_SCROLL_ALWAYS
-                || (overScrollMode == View.OVER_SCROLL_IF_CONTENT_SCROLLS
-                        && mAdapter != null && mAdapter.getCount() > 1)) {
-            if (!mLeftEdge.isFinished()) {
-                final int restoreCount = canvas.save();
-                final int height = getHeight() - getPaddingTop() - getPaddingBottom();
-                final int width = getWidth();
-
-                canvas.rotate(270);
-                canvas.translate(-height + getPaddingTop(), mFirstOffset * width);
-                mLeftEdge.setSize(height, width);
-                needsInvalidate |= mLeftEdge.draw(canvas);
-                canvas.restoreToCount(restoreCount);
-            }
-            if (!mRightEdge.isFinished()) {
-                final int restoreCount = canvas.save();
-                final int width = getWidth();
-                final int height = getHeight() - getPaddingTop() - getPaddingBottom();
-
-                canvas.rotate(90);
-                canvas.translate(-getPaddingTop(), -(mLastOffset + 1) * width);
-                mRightEdge.setSize(height, width);
-                needsInvalidate |= mRightEdge.draw(canvas);
-                canvas.restoreToCount(restoreCount);
-            }
-        } else {
-            mLeftEdge.finish();
-            mRightEdge.finish();
-        }
-
-        if (needsInvalidate) {
-            // Keep animating
-            ViewCompat.postInvalidateOnAnimation(this);
-        }
-    }
-
-    @Override
-    protected void onDraw(Canvas canvas) {
-        super.onDraw(canvas);
-
-        // Draw the margin drawable between pages if needed.
-        if (mPageMargin > 0 && mMarginDrawable != null && mItems.size() > 0 && mAdapter != null) {
-            final int scrollX = getScrollX();
-            final int width = getWidth();
-
-            final float marginOffset = (float) mPageMargin / width;
-            int itemIndex = 0;
-            ItemInfo ii = mItems.get(0);
-            float offset = ii.offset;
-            final int itemCount = mItems.size();
-            final int firstPos = ii.position;
-            final int lastPos = mItems.get(itemCount - 1).position;
-            for (int pos = firstPos; pos < lastPos; pos++) {
-                while (pos > ii.position && itemIndex < itemCount) {
-                    ii = mItems.get(++itemIndex);
-                }
-
-                float drawAt;
-                if (pos == ii.position) {
-                    drawAt = (ii.offset + ii.widthFactor) * width;
-                    offset = ii.offset + ii.widthFactor + marginOffset;
-                } else {
-                    float widthFactor = mAdapter.getPageWidth(pos);
-                    drawAt = (offset + widthFactor) * width;
-                    offset += widthFactor + marginOffset;
-                }
-
-                if (drawAt + mPageMargin > scrollX) {
-                    mMarginDrawable.setBounds(Math.round(drawAt), mTopPageBounds,
-                            Math.round(drawAt + mPageMargin), mBottomPageBounds);
-                    mMarginDrawable.draw(canvas);
-                }
-
-                if (drawAt > scrollX + width) {
-                    break; // No more visible, no sense in continuing
-                }
-            }
-        }
-    }
-
-    /**
-     * Start a fake drag of the pager.
-     *
-     * <p>A fake drag can be useful if you want to synchronize the motion of the ViewPager
-     * with the touch scrolling of another view, while still letting the ViewPager
-     * control the snapping motion and fling behavior. (e.g. parallax-scrolling tabs.)
-     * Call {@link #fakeDragBy(float)} to simulate the actual drag motion. Call
-     * {@link #endFakeDrag()} to complete the fake drag and fling as necessary.
-     *
-     * <p>During a fake drag the ViewPager will ignore all touch events. If a real drag
-     * is already in progress, this method will return false.
-     *
-     * @return true if the fake drag began successfully, false if it could not be started.
-     *
-     * @see #fakeDragBy(float)
-     * @see #endFakeDrag()
-     */
-    public boolean beginFakeDrag() {
-        if (mIsBeingDragged) {
-            return false;
-        }
-        mFakeDragging = true;
-        setScrollState(SCROLL_STATE_DRAGGING);
-        mInitialMotionX = mLastMotionX = 0;
-        if (mVelocityTracker == null) {
-            mVelocityTracker = VelocityTracker.obtain();
-        } else {
-            mVelocityTracker.clear();
-        }
-        final long time = SystemClock.uptimeMillis();
-        final MotionEvent ev = MotionEvent.obtain(time, time, MotionEvent.ACTION_DOWN, 0, 0, 0);
-        mVelocityTracker.addMovement(ev);
-        ev.recycle();
-        mFakeDragBeginTime = time;
-        return true;
-    }
-
-    /**
-     * End a fake drag of the pager.
-     *
-     * @see #beginFakeDrag()
-     * @see #fakeDragBy(float)
-     */
-    public void endFakeDrag() {
-        if (!mFakeDragging) {
-            throw new IllegalStateException("No fake drag in progress. Call beginFakeDrag first.");
-        }
-
-        if (mAdapter != null) {
-            final VelocityTracker velocityTracker = mVelocityTracker;
-            velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
-            int initialVelocity = (int) velocityTracker.getXVelocity(mActivePointerId);
-            mPopulatePending = true;
-            final int width = getClientWidth();
-            final int scrollX = getScrollX();
-            final ItemInfo ii = infoForCurrentScrollPosition();
-            final int currentPage = ii.position;
-            final float pageOffset = (((float) scrollX / width) - ii.offset) / ii.widthFactor;
-            final int totalDelta = (int) (mLastMotionX - mInitialMotionX);
-            int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity,
-                    totalDelta);
-            setCurrentItemInternal(nextPage, true, true, initialVelocity);
-        }
-        endDrag();
-
-        mFakeDragging = false;
-    }
-
-    /**
-     * Fake drag by an offset in pixels. You must have called {@link #beginFakeDrag()} first.
-     *
-     * @param xOffset Offset in pixels to drag by.
-     * @see #beginFakeDrag()
-     * @see #endFakeDrag()
-     */
-    public void fakeDragBy(float xOffset) {
-        if (!mFakeDragging) {
-            throw new IllegalStateException("No fake drag in progress. Call beginFakeDrag first.");
-        }
-
-        if (mAdapter == null) {
-            return;
-        }
-
-        mLastMotionX += xOffset;
-
-        float oldScrollX = getScrollX();
-        float scrollX = oldScrollX - xOffset;
-        final int width = getClientWidth();
-
-        float leftBound = width * mFirstOffset;
-        float rightBound = width * mLastOffset;
-
-        final ItemInfo firstItem = mItems.get(0);
-        final ItemInfo lastItem = mItems.get(mItems.size() - 1);
-        if (firstItem.position != 0) {
-            leftBound = firstItem.offset * width;
-        }
-        if (lastItem.position != mAdapter.getCount() - 1) {
-            rightBound = lastItem.offset * width;
-        }
-
-        if (scrollX < leftBound) {
-            scrollX = leftBound;
-        } else if (scrollX > rightBound) {
-            scrollX = rightBound;
-        }
-        // Don't lose the rounded component
-        mLastMotionX += scrollX - (int) scrollX;
-        scrollTo((int) scrollX, getScrollY());
-        pageScrolled((int) scrollX);
-
-        // Synthesize an event for the VelocityTracker.
-        final long time = SystemClock.uptimeMillis();
-        final MotionEvent ev = MotionEvent.obtain(mFakeDragBeginTime, time, MotionEvent.ACTION_MOVE,
-                mLastMotionX, 0, 0);
-        mVelocityTracker.addMovement(ev);
-        ev.recycle();
-    }
-
-    /**
-     * Returns true if a fake drag is in progress.
-     *
-     * @return true if currently in a fake drag, false otherwise.
-     *
-     * @see #beginFakeDrag()
-     * @see #fakeDragBy(float)
-     * @see #endFakeDrag()
-     */
-    public boolean isFakeDragging() {
-        return mFakeDragging;
-    }
-
-    private void onSecondaryPointerUp(MotionEvent ev) {
-        final int pointerIndex = ev.getActionIndex();
-        final int pointerId = ev.getPointerId(pointerIndex);
-        if (pointerId == mActivePointerId) {
-            // This was our active pointer going up. Choose a new
-            // active pointer and adjust accordingly.
-            final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
-            mLastMotionX = ev.getX(newPointerIndex);
-            mActivePointerId = ev.getPointerId(newPointerIndex);
-            if (mVelocityTracker != null) {
-                mVelocityTracker.clear();
-            }
-        }
-    }
-
-    private void endDrag() {
-        mIsBeingDragged = false;
-        mIsUnableToDrag = false;
-
-        if (mVelocityTracker != null) {
-            mVelocityTracker.recycle();
-            mVelocityTracker = null;
-        }
-    }
-
-    private void setScrollingCacheEnabled(boolean enabled) {
-        if (mScrollingCacheEnabled != enabled) {
-            mScrollingCacheEnabled = enabled;
-            if (USE_CACHE) {
-                final int size = getChildCount();
-                for (int i = 0; i < size; ++i) {
-                    final View child = getChildAt(i);
-                    if (child.getVisibility() != GONE) {
-                        child.setDrawingCacheEnabled(enabled);
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Check if this ViewPager can be scrolled horizontally in a certain direction.
-     *
-     * @param direction Negative to check scrolling left, positive to check scrolling right.
-     * @return Whether this ViewPager can be scrolled in the specified direction. It will always
-     *         return false if the specified direction is 0.
-     */
-    @Override
-    public boolean canScrollHorizontally(int direction) {
-        if (mAdapter == null) {
-            return false;
-        }
-
-        final int width = getClientWidth();
-        final int scrollX = getScrollX();
-        if (direction < 0) {
-            return (scrollX > (int) (width * mFirstOffset));
-        } else if (direction > 0) {
-            return (scrollX < (int) (width * mLastOffset));
-        } else {
-            return false;
-        }
-    }
-
-    /**
-     * Tests scrollability within child views of v given a delta of dx.
-     *
-     * @param v View to test for horizontal scrollability
-     * @param checkV Whether the view v passed should itself be checked for scrollability (true),
-     *               or just its children (false).
-     * @param dx Delta scrolled in pixels
-     * @param x X coordinate of the active touch point
-     * @param y Y coordinate of the active touch point
-     * @return true if child views of v can be scrolled by delta of dx.
-     */
-    protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
-        if (v instanceof ViewGroup) {
-            final ViewGroup group = (ViewGroup) v;
-            final int scrollX = v.getScrollX();
-            final int scrollY = v.getScrollY();
-            final int count = group.getChildCount();
-            // Count backwards - let topmost views consume scroll distance first.
-            for (int i = count - 1; i >= 0; i--) {
-                // TODO: Add versioned support here for transformed views.
-                // This will not work for transformed views in Honeycomb+
-                final View child = group.getChildAt(i);
-                if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight()
-                        && y + scrollY >= child.getTop() && y + scrollY < child.getBottom()
-                        && canScroll(child, true, dx, x + scrollX - child.getLeft(),
-                                y + scrollY - child.getTop())) {
-                    return true;
-                }
-            }
-        }
-
-        return checkV && v.canScrollHorizontally(-dx);
-    }
-
-    @Override
-    public boolean dispatchKeyEvent(KeyEvent event) {
-        // Let the focused view and/or our descendants get the key first
-        return super.dispatchKeyEvent(event) || executeKeyEvent(event);
-    }
-
-    /**
-     * You can call this function yourself to have the scroll view perform
-     * scrolling from a key event, just as if the event had been dispatched to
-     * it by the view hierarchy.
-     *
-     * @param event The key event to execute.
-     * @return Return true if the event was handled, else false.
-     */
-    public boolean executeKeyEvent(@NonNull KeyEvent event) {
-        boolean handled = false;
-        if (event.getAction() == KeyEvent.ACTION_DOWN) {
-            switch (event.getKeyCode()) {
-                case KeyEvent.KEYCODE_DPAD_LEFT:
-                    if (event.hasModifiers(KeyEvent.META_ALT_ON)) {
-                        handled = pageLeft();
-                    } else {
-                        handled = arrowScroll(FOCUS_LEFT);
-                    }
-                    break;
-                case KeyEvent.KEYCODE_DPAD_RIGHT:
-                    if (event.hasModifiers(KeyEvent.META_ALT_ON)) {
-                        handled = pageRight();
-                    } else {
-                        handled = arrowScroll(FOCUS_RIGHT);
-                    }
-                    break;
-                case KeyEvent.KEYCODE_TAB:
-                    if (event.hasNoModifiers()) {
-                        handled = arrowScroll(FOCUS_FORWARD);
-                    } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
-                        handled = arrowScroll(FOCUS_BACKWARD);
-                    }
-                    break;
-            }
-        }
-        return handled;
-    }
-
-    /**
-     * Handle scrolling in response to a left or right arrow click.
-     *
-     * @param direction The direction corresponding to the arrow key that was pressed. It should be
-     *                  either {@link View#FOCUS_LEFT} or {@link View#FOCUS_RIGHT}.
-     * @return Whether the scrolling was handled successfully.
-     */
-    public boolean arrowScroll(int direction) {
-        View currentFocused = findFocus();
-        if (currentFocused == this) {
-            currentFocused = null;
-        } else if (currentFocused != null) {
-            boolean isChild = false;
-            for (ViewParent parent = currentFocused.getParent(); parent instanceof ViewGroup;
-                    parent = parent.getParent()) {
-                if (parent == this) {
-                    isChild = true;
-                    break;
-                }
-            }
-            if (!isChild) {
-                // This would cause the focus search down below to fail in fun ways.
-                final StringBuilder sb = new StringBuilder();
-                sb.append(currentFocused.getClass().getSimpleName());
-                for (ViewParent parent = currentFocused.getParent(); parent instanceof ViewGroup;
-                        parent = parent.getParent()) {
-                    sb.append(" => ").append(parent.getClass().getSimpleName());
-                }
-                Log.e(TAG, "arrowScroll tried to find focus based on non-child "
-                        + "current focused view " + sb.toString());
-                currentFocused = null;
-            }
-        }
-
-        boolean handled = false;
-
-        View nextFocused = FocusFinder.getInstance().findNextFocus(this, currentFocused,
-                direction);
-        if (nextFocused != null && nextFocused != currentFocused) {
-            if (direction == View.FOCUS_LEFT) {
-                // If there is nothing to the left, or this is causing us to
-                // jump to the right, then what we really want to do is page left.
-                final int nextLeft = getChildRectInPagerCoordinates(mTempRect, nextFocused).left;
-                final int currLeft = getChildRectInPagerCoordinates(mTempRect, currentFocused).left;
-                if (currentFocused != null && nextLeft >= currLeft) {
-                    handled = pageLeft();
-                } else {
-                    handled = nextFocused.requestFocus();
-                }
-            } else if (direction == View.FOCUS_RIGHT) {
-                // If there is nothing to the right, or this is causing us to
-                // jump to the left, then what we really want to do is page right.
-                final int nextLeft = getChildRectInPagerCoordinates(mTempRect, nextFocused).left;
-                final int currLeft = getChildRectInPagerCoordinates(mTempRect, currentFocused).left;
-                if (currentFocused != null && nextLeft <= currLeft) {
-                    handled = pageRight();
-                } else {
-                    handled = nextFocused.requestFocus();
-                }
-            }
-        } else if (direction == FOCUS_LEFT || direction == FOCUS_BACKWARD) {
-            // Trying to move left and nothing there; try to page.
-            handled = pageLeft();
-        } else if (direction == FOCUS_RIGHT || direction == FOCUS_FORWARD) {
-            // Trying to move right and nothing there; try to page.
-            handled = pageRight();
-        }
-        if (handled) {
-            playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction));
-        }
-        return handled;
-    }
-
-    private Rect getChildRectInPagerCoordinates(Rect outRect, View child) {
-        if (outRect == null) {
-            outRect = new Rect();
-        }
-        if (child == null) {
-            outRect.set(0, 0, 0, 0);
-            return outRect;
-        }
-        outRect.left = child.getLeft();
-        outRect.right = child.getRight();
-        outRect.top = child.getTop();
-        outRect.bottom = child.getBottom();
-
-        ViewParent parent = child.getParent();
-        while (parent instanceof ViewGroup && parent != this) {
-            final ViewGroup group = (ViewGroup) parent;
-            outRect.left += group.getLeft();
-            outRect.right += group.getRight();
-            outRect.top += group.getTop();
-            outRect.bottom += group.getBottom();
-
-            parent = group.getParent();
-        }
-        return outRect;
-    }
-
-    boolean pageLeft() {
-        if (mCurItem > 0) {
-            setCurrentItem(mCurItem - 1, true);
-            return true;
-        }
-        return false;
-    }
-
-    boolean pageRight() {
-        if (mAdapter != null && mCurItem < (mAdapter.getCount() - 1)) {
-            setCurrentItem(mCurItem + 1, true);
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * We only want the current page that is being shown to be focusable.
-     */
-    @Override
-    public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
-        final int focusableCount = views.size();
-
-        final int descendantFocusability = getDescendantFocusability();
-
-        if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
-            for (int i = 0; i < getChildCount(); i++) {
-                final View child = getChildAt(i);
-                if (child.getVisibility() == VISIBLE) {
-                    ItemInfo ii = infoForChild(child);
-                    if (ii != null && ii.position == mCurItem) {
-                        child.addFocusables(views, direction, focusableMode);
-                    }
-                }
-            }
-        }
-
-        // we add ourselves (if focusable) in all cases except for when we are
-        // FOCUS_AFTER_DESCENDANTS and there are some descendants focusable.  this is
-        // to avoid the focus search finding layouts when a more precise search
-        // among the focusable children would be more interesting.
-        if (descendantFocusability != FOCUS_AFTER_DESCENDANTS
-                || (focusableCount == views.size())) { // No focusable descendants
-            // Note that we can't call the superclass here, because it will
-            // add all views in.  So we need to do the same thing View does.
-            if (!isFocusable()) {
-                return;
-            }
-            if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE
-                    && isInTouchMode() && !isFocusableInTouchMode()) {
-                return;
-            }
-            if (views != null) {
-                views.add(this);
-            }
-        }
-    }
-
-    /**
-     * We only want the current page that is being shown to be touchable.
-     */
-    @Override
-    public void addTouchables(ArrayList<View> views) {
-        // Note that we don't call super.addTouchables(), which means that
-        // we don't call View.addTouchables().  This is okay because a ViewPager
-        // is itself not touchable.
-        for (int i = 0; i < getChildCount(); i++) {
-            final View child = getChildAt(i);
-            if (child.getVisibility() == VISIBLE) {
-                ItemInfo ii = infoForChild(child);
-                if (ii != null && ii.position == mCurItem) {
-                    child.addTouchables(views);
-                }
-            }
-        }
-    }
-
-    /**
-     * We only want the current page that is being shown to be focusable.
-     */
-    @Override
-    protected boolean onRequestFocusInDescendants(int direction,
-            Rect previouslyFocusedRect) {
-        int index;
-        int increment;
-        int end;
-        int count = getChildCount();
-        if ((direction & FOCUS_FORWARD) != 0) {
-            index = 0;
-            increment = 1;
-            end = count;
-        } else {
-            index = count - 1;
-            increment = -1;
-            end = -1;
-        }
-        for (int i = index; i != end; i += increment) {
-            View child = getChildAt(i);
-            if (child.getVisibility() == VISIBLE) {
-                ItemInfo ii = infoForChild(child);
-                if (ii != null && ii.position == mCurItem) {
-                    if (child.requestFocus(direction, previouslyFocusedRect)) {
-                        return true;
-                    }
-                }
-            }
-        }
-        return false;
-    }
-
-    @Override
-    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
-        // Dispatch scroll events from this ViewPager.
-        if (event.getEventType() == AccessibilityEventCompat.TYPE_VIEW_SCROLLED) {
-            return super.dispatchPopulateAccessibilityEvent(event);
-        }
-
-        // Dispatch all other accessibility events from the current page.
-        final int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            final View child = getChildAt(i);
-            if (child.getVisibility() == VISIBLE) {
-                final ItemInfo ii = infoForChild(child);
-                if (ii != null && ii.position == mCurItem
-                        && child.dispatchPopulateAccessibilityEvent(event)) {
-                    return true;
-                }
-            }
-        }
-
-        return false;
-    }
-
-    @Override
-    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
-        return new LayoutParams();
-    }
-
-    @Override
-    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
-        return generateDefaultLayoutParams();
-    }
-
-    @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);
-    }
-
-    class MyAccessibilityDelegate extends AccessibilityDelegateCompat {
-
-        @Override
-        public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
-            super.onInitializeAccessibilityEvent(host, event);
-            event.setClassName(ViewPager.class.getName());
-            event.setScrollable(canScroll());
-            if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED && mAdapter != null) {
-                event.setItemCount(mAdapter.getCount());
-                event.setFromIndex(mCurItem);
-                event.setToIndex(mCurItem);
-            }
-        }
-
-        @Override
-        public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
-            super.onInitializeAccessibilityNodeInfo(host, info);
-            info.setClassName(ViewPager.class.getName());
-            info.setScrollable(canScroll());
-            if (canScrollHorizontally(1)) {
-                info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD);
-            }
-            if (canScrollHorizontally(-1)) {
-                info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD);
-            }
-        }
-
-        @Override
-        public boolean performAccessibilityAction(View host, int action, Bundle args) {
-            if (super.performAccessibilityAction(host, action, args)) {
-                return true;
-            }
-            switch (action) {
-                case AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD: {
-                    if (canScrollHorizontally(1)) {
-                        setCurrentItem(mCurItem + 1);
-                        return true;
-                    }
-                } return false;
-                case AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD: {
-                    if (canScrollHorizontally(-1)) {
-                        setCurrentItem(mCurItem - 1);
-                        return true;
-                    }
-                } return false;
-            }
-            return false;
-        }
-
-        private boolean canScroll() {
-            return (mAdapter != null) && (mAdapter.getCount() > 1);
-        }
-    }
-
-    private class PagerObserver extends DataSetObserver {
-        PagerObserver() {
-        }
-
-        @Override
-        public void onChanged() {
-            dataSetChanged();
-        }
-        @Override
-        public void onInvalidated() {
-            dataSetChanged();
-        }
-    }
-
-    /**
-     * Layout parameters that should be supplied for views added to a
-     * ViewPager.
-     */
-    public static class LayoutParams extends ViewGroup.LayoutParams {
-        /**
-         * true if this view is a decoration on the pager itself and not
-         * a view supplied by the adapter.
-         */
-        public boolean isDecor;
-
-        /**
-         * Gravity setting for use on decor views only:
-         * Where to position the view page within the overall ViewPager
-         * container; constants are defined in {@link android.view.Gravity}.
-         */
-        public int gravity;
-
-        /**
-         * Width as a 0-1 multiplier of the measured pager width
-         */
-        float widthFactor = 0.f;
-
-        /**
-         * true if this view was added during layout and needs to be measured
-         * before being positioned.
-         */
-        boolean needsMeasure;
-
-        /**
-         * Adapter position this view is for if !isDecor
-         */
-        int position;
-
-        /**
-         * Current child index within the ViewPager that this view occupies
-         */
-        int childIndex;
-
-        public LayoutParams() {
-            super(MATCH_PARENT, MATCH_PARENT);
-        }
-
-        public LayoutParams(Context context, AttributeSet attrs) {
-            super(context, attrs);
-
-            final TypedArray a = context.obtainStyledAttributes(attrs, LAYOUT_ATTRS);
-            gravity = a.getInteger(0, Gravity.TOP);
-            a.recycle();
-        }
-    }
-
-    static class ViewPositionComparator implements Comparator<View> {
-        @Override
-        public int compare(View lhs, View rhs) {
-            final LayoutParams llp = (LayoutParams) lhs.getLayoutParams();
-            final LayoutParams rlp = (LayoutParams) rhs.getLayoutParams();
-            if (llp.isDecor != rlp.isDecor) {
-                return llp.isDecor ? 1 : -1;
-            }
-            return llp.position - rlp.position;
-        }
-    }
-}
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/src/main/java/android/support/v4/widget/SlidingPaneLayout.java b/core-ui/src/main/java/android/support/v4/widget/SlidingPaneLayout.java
deleted file mode 100644
index 5676ccf..0000000
--- a/core-ui/src/main/java/android/support/v4/widget/SlidingPaneLayout.java
+++ /dev/null
@@ -1,1645 +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.
- */
-
-package android.support.v4.widget;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.PixelFormat;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffColorFilter;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.support.annotation.ColorInt;
-import android.support.annotation.DrawableRes;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.RequiresApi;
-import android.support.v4.content.ContextCompat;
-import android.support.v4.view.AbsSavedState;
-import android.support.v4.view.AccessibilityDelegateCompat;
-import android.support.v4.view.ViewCompat;
-import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewParent;
-import android.view.accessibility.AccessibilityEvent;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-
-/**
- * SlidingPaneLayout provides a horizontal, multi-pane layout for use at the top level
- * of a UI. A left (or first) pane is treated as a content list or browser, subordinate to a
- * primary detail view for displaying content.
- *
- * <p>Child views may overlap if their combined width exceeds the available width
- * in the SlidingPaneLayout. When this occurs the user may slide the topmost view out of the way
- * by dragging it, or by navigating in the direction of the overlapped view using a keyboard.
- * If the content of the dragged child view is itself horizontally scrollable, the user may
- * grab it by the very edge.</p>
- *
- * <p>Thanks to this sliding behavior, SlidingPaneLayout may be suitable for creating layouts
- * that can smoothly adapt across many different screen sizes, expanding out fully on larger
- * screens and collapsing on smaller screens.</p>
- *
- * <p>SlidingPaneLayout is distinct from a navigation drawer as described in the design
- * guide and should not be used in the same scenarios. SlidingPaneLayout should be thought
- * of only as a way to allow a two-pane layout normally used on larger screens to adapt to smaller
- * screens in a natural way. The interaction patterns expressed by SlidingPaneLayout imply
- * a physicality and direct information hierarchy between panes that does not necessarily exist
- * in a scenario where a navigation drawer should be used instead.</p>
- *
- * <p>Appropriate uses of SlidingPaneLayout include pairings of panes such as a contact list and
- * subordinate interactions with those contacts, or an email thread list with the content pane
- * displaying the contents of the selected thread. Inappropriate uses of SlidingPaneLayout include
- * switching between disparate functions of your app, such as jumping from a social stream view
- * to a view of your personal profile - cases such as this should use the navigation drawer
- * pattern instead. ({@link DrawerLayout DrawerLayout} implements this pattern.)</p>
- *
- * <p>Like {@link android.widget.LinearLayout LinearLayout}, SlidingPaneLayout supports
- * the use of the layout parameter <code>layout_weight</code> on child views to determine
- * how to divide leftover space after measurement is complete. It is only relevant for width.
- * When views do not overlap weight behaves as it does in a LinearLayout.</p>
- *
- * <p>When views do overlap, weight on a slideable pane indicates that the pane should be
- * sized to fill all available space in the closed state. Weight on a pane that becomes covered
- * indicates that the pane should be sized to fill all available space except a small minimum strip
- * that the user may use to grab the slideable view and pull it back over into a closed state.</p>
- */
-public class SlidingPaneLayout extends ViewGroup {
-    private static final String TAG = "SlidingPaneLayout";
-
-    /**
-     * Default size of the overhang for a pane in the open state.
-     * At least this much of a sliding pane will remain visible.
-     * This indicates that there is more content available and provides
-     * a "physical" edge to grab to pull it closed.
-     */
-    private static final int DEFAULT_OVERHANG_SIZE = 32; // dp;
-
-    /**
-     * If no fade color is given by default it will fade to 80% gray.
-     */
-    private static final int DEFAULT_FADE_COLOR = 0xcccccccc;
-
-    /**
-     * The fade color used for the sliding panel. 0 = no fading.
-     */
-    private int mSliderFadeColor = DEFAULT_FADE_COLOR;
-
-    /**
-     * Minimum velocity that will be detected as a fling
-     */
-    private static final int MIN_FLING_VELOCITY = 400; // dips per second
-
-    /**
-     * The fade color used for the panel covered by the slider. 0 = no fading.
-     */
-    private int mCoveredFadeColor;
-
-    /**
-     * Drawable used to draw the shadow between panes by default.
-     */
-    private Drawable mShadowDrawableLeft;
-
-    /**
-     * Drawable used to draw the shadow between panes to support RTL (right to left language).
-     */
-    private Drawable mShadowDrawableRight;
-
-    /**
-     * The size of the overhang in pixels.
-     * This is the minimum section of the sliding panel that will
-     * be visible in the open state to allow for a closing drag.
-     */
-    private final int mOverhangSize;
-
-    /**
-     * True if a panel can slide with the current measurements
-     */
-    private boolean mCanSlide;
-
-    /**
-     * The child view that can slide, if any.
-     */
-    View mSlideableView;
-
-    /**
-     * How far the panel is offset from its closed position.
-     * range [0, 1] where 0 = closed, 1 = open.
-     */
-    float mSlideOffset;
-
-    /**
-     * How far the non-sliding panel is parallaxed from its usual position when open.
-     * range [0, 1]
-     */
-    private float mParallaxOffset;
-
-    /**
-     * How far in pixels the slideable panel may move.
-     */
-    int mSlideRange;
-
-    /**
-     * A panel view is locked into internal scrolling or another condition that
-     * is preventing a drag.
-     */
-    boolean mIsUnableToDrag;
-
-    /**
-     * Distance in pixels to parallax the fixed pane by when fully closed
-     */
-    private int mParallaxBy;
-
-    private float mInitialMotionX;
-    private float mInitialMotionY;
-
-    private PanelSlideListener mPanelSlideListener;
-
-    final ViewDragHelper mDragHelper;
-
-    /**
-     * Stores whether or not the pane was open the last time it was slideable.
-     * If open/close operations are invoked this state is modified. Used by
-     * instance state save/restore.
-     */
-    boolean mPreservedOpenState;
-    private boolean mFirstLayout = true;
-
-    private final Rect mTmpRect = new Rect();
-
-    final ArrayList<DisableLayerRunnable> mPostedRunnables = new ArrayList<>();
-
-    static final SlidingPanelLayoutImpl IMPL;
-
-    static {
-        if (Build.VERSION.SDK_INT >= 17) {
-            IMPL = new SlidingPanelLayoutImplJBMR1();
-        } else if (Build.VERSION.SDK_INT >= 16) {
-            IMPL = new SlidingPanelLayoutImplJB();
-        } else {
-            IMPL = new SlidingPanelLayoutImplBase();
-        }
-    }
-
-    /**
-     * Listener for monitoring events about sliding panes.
-     */
-    public interface PanelSlideListener {
-        /**
-         * Called when a sliding pane's position changes.
-         * @param panel The child view that was moved
-         * @param slideOffset The new offset of this sliding pane within its range, from 0-1
-         */
-        void onPanelSlide(@NonNull View panel, float slideOffset);
-        /**
-         * Called when a sliding pane becomes slid completely open. The pane may or may not
-         * be interactive at this point depending on how much of the pane is visible.
-         * @param panel The child view that was slid to an open position, revealing other panes
-         */
-        void onPanelOpened(@NonNull View panel);
-
-        /**
-         * Called when a sliding pane becomes slid completely closed. The pane is now guaranteed
-         * to be interactive. It may now obscure other views in the layout.
-         * @param panel The child view that was slid to a closed position
-         */
-        void onPanelClosed(@NonNull View panel);
-    }
-
-    /**
-     * No-op stubs for {@link PanelSlideListener}. If you only want to implement a subset
-     * of the listener methods you can extend this instead of implement the full interface.
-     */
-    public static class SimplePanelSlideListener implements PanelSlideListener {
-        @Override
-        public void onPanelSlide(View panel, float slideOffset) {
-        }
-        @Override
-        public void onPanelOpened(View panel) {
-        }
-        @Override
-        public void onPanelClosed(View panel) {
-        }
-    }
-
-    public SlidingPaneLayout(@NonNull Context context) {
-        this(context, null);
-    }
-
-    public SlidingPaneLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public SlidingPaneLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-
-        final float density = context.getResources().getDisplayMetrics().density;
-        mOverhangSize = (int) (DEFAULT_OVERHANG_SIZE * density + 0.5f);
-
-        setWillNotDraw(false);
-
-        ViewCompat.setAccessibilityDelegate(this, new AccessibilityDelegate());
-        ViewCompat.setImportantForAccessibility(this, ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
-
-        mDragHelper = ViewDragHelper.create(this, 0.5f, new DragHelperCallback());
-        mDragHelper.setMinVelocity(MIN_FLING_VELOCITY * density);
-    }
-
-    /**
-     * Set a distance to parallax the lower pane by when the upper pane is in its
-     * fully closed state. The lower pane will scroll between this position and
-     * its fully open state.
-     *
-     * @param parallaxBy Distance to parallax by in pixels
-     */
-    public void setParallaxDistance(int parallaxBy) {
-        mParallaxBy = parallaxBy;
-        requestLayout();
-    }
-
-    /**
-     * @return The distance the lower pane will parallax by when the upper pane is fully closed.
-     *
-     * @see #setParallaxDistance(int)
-     */
-    public int getParallaxDistance() {
-        return mParallaxBy;
-    }
-
-    /**
-     * Set the color used to fade the sliding pane out when it is slid most of the way offscreen.
-     *
-     * @param color An ARGB-packed color value
-     */
-    public void setSliderFadeColor(@ColorInt int color) {
-        mSliderFadeColor = color;
-    }
-
-    /**
-     * @return The ARGB-packed color value used to fade the sliding pane
-     */
-    @ColorInt
-    public int getSliderFadeColor() {
-        return mSliderFadeColor;
-    }
-
-    /**
-     * Set the color used to fade the pane covered by the sliding pane out when the pane
-     * will become fully covered in the closed state.
-     *
-     * @param color An ARGB-packed color value
-     */
-    public void setCoveredFadeColor(@ColorInt int color) {
-        mCoveredFadeColor = color;
-    }
-
-    /**
-     * @return The ARGB-packed color value used to fade the fixed pane
-     */
-    @ColorInt
-    public int getCoveredFadeColor() {
-        return mCoveredFadeColor;
-    }
-
-    public void setPanelSlideListener(@Nullable PanelSlideListener listener) {
-        mPanelSlideListener = listener;
-    }
-
-    void dispatchOnPanelSlide(View panel) {
-        if (mPanelSlideListener != null) {
-            mPanelSlideListener.onPanelSlide(panel, mSlideOffset);
-        }
-    }
-
-    void dispatchOnPanelOpened(View panel) {
-        if (mPanelSlideListener != null) {
-            mPanelSlideListener.onPanelOpened(panel);
-        }
-        sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
-    }
-
-    void dispatchOnPanelClosed(View panel) {
-        if (mPanelSlideListener != null) {
-            mPanelSlideListener.onPanelClosed(panel);
-        }
-        sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
-    }
-
-    void updateObscuredViewsVisibility(View panel) {
-        final boolean isLayoutRtl = isLayoutRtlSupport();
-        final int startBound = isLayoutRtl ? (getWidth() - getPaddingRight()) : getPaddingLeft();
-        final int endBound = isLayoutRtl ? getPaddingLeft() : (getWidth() - getPaddingRight());
-        final int topBound = getPaddingTop();
-        final int bottomBound = getHeight() - getPaddingBottom();
-        final int left;
-        final int right;
-        final int top;
-        final int bottom;
-        if (panel != null && viewIsOpaque(panel)) {
-            left = panel.getLeft();
-            right = panel.getRight();
-            top = panel.getTop();
-            bottom = panel.getBottom();
-        } else {
-            left = right = top = bottom = 0;
-        }
-
-        for (int i = 0, childCount = getChildCount(); i < childCount; i++) {
-            final View child = getChildAt(i);
-
-            if (child == panel) {
-                // There are still more children above the panel but they won't be affected.
-                break;
-            } else if (child.getVisibility() == GONE) {
-                continue;
-            }
-
-            final int clampedChildLeft = Math.max(
-                    (isLayoutRtl ? endBound : startBound), child.getLeft());
-            final int clampedChildTop = Math.max(topBound, child.getTop());
-            final int clampedChildRight = Math.min(
-                    (isLayoutRtl ? startBound : endBound), child.getRight());
-            final int clampedChildBottom = Math.min(bottomBound, child.getBottom());
-            final int vis;
-            if (clampedChildLeft >= left && clampedChildTop >= top
-                    && clampedChildRight <= right && clampedChildBottom <= bottom) {
-                vis = INVISIBLE;
-            } else {
-                vis = VISIBLE;
-            }
-            child.setVisibility(vis);
-        }
-    }
-
-    void setAllChildrenVisible() {
-        for (int i = 0, childCount = getChildCount(); i < childCount; i++) {
-            final View child = getChildAt(i);
-            if (child.getVisibility() == INVISIBLE) {
-                child.setVisibility(VISIBLE);
-            }
-        }
-    }
-
-    private static boolean viewIsOpaque(View v) {
-        if (v.isOpaque()) {
-            return true;
-        }
-
-        // View#isOpaque didn't take all valid opaque scrollbar modes into account
-        // before API 18 (JB-MR2). On newer devices rely solely on isOpaque above and return false
-        // here. On older devices, check the view's background drawable directly as a fallback.
-        if (Build.VERSION.SDK_INT >= 18) {
-            return false;
-        }
-
-        final Drawable bg = v.getBackground();
-        if (bg != null) {
-            return bg.getOpacity() == PixelFormat.OPAQUE;
-        }
-        return false;
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        mFirstLayout = true;
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        mFirstLayout = true;
-
-        for (int i = 0, count = mPostedRunnables.size(); i < count; i++) {
-            final DisableLayerRunnable dlr = mPostedRunnables.get(i);
-            dlr.run();
-        }
-        mPostedRunnables.clear();
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
-        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
-        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
-        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
-
-        if (widthMode != 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;
-                }
-            } else {
-                throw new IllegalStateException("Width must have an exact value or MATCH_PARENT");
-            }
-        } else if (heightMode == MeasureSpec.UNSPECIFIED) {
-            if (isInEditMode()) {
-                // Don't crash the layout editor. Pick a magic number from thin air instead.
-                // TODO Better communication with tools of this bogus state.
-                // It will crash on a real device.
-                if (heightMode == MeasureSpec.UNSPECIFIED) {
-                    heightMode = MeasureSpec.AT_MOST;
-                    heightSize = 300;
-                }
-            } else {
-                throw new IllegalStateException("Height must not be UNSPECIFIED");
-            }
-        }
-
-        int layoutHeight = 0;
-        int maxLayoutHeight = 0;
-        switch (heightMode) {
-            case MeasureSpec.EXACTLY:
-                layoutHeight = maxLayoutHeight = heightSize - getPaddingTop() - getPaddingBottom();
-                break;
-            case MeasureSpec.AT_MOST:
-                maxLayoutHeight = heightSize - getPaddingTop() - getPaddingBottom();
-                break;
-        }
-
-        float weightSum = 0;
-        boolean canSlide = false;
-        final int widthAvailable = widthSize - getPaddingLeft() - getPaddingRight();
-        int widthRemaining = widthAvailable;
-        final int childCount = getChildCount();
-
-        if (childCount > 2) {
-            Log.e(TAG, "onMeasure: More than two child views are not supported.");
-        }
-
-        // We'll find the current one below.
-        mSlideableView = null;
-
-        // First pass. Measure based on child LayoutParams width/height.
-        // Weight will incur a second pass.
-        for (int i = 0; i < childCount; i++) {
-            final View child = getChildAt(i);
-            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-
-            if (child.getVisibility() == GONE) {
-                lp.dimWhenOffset = false;
-                continue;
-            }
-
-            if (lp.weight > 0) {
-                weightSum += lp.weight;
-
-                // If we have no width, weight is the only contributor to the final size.
-                // Measure this view on the weight pass only.
-                if (lp.width == 0) continue;
-            }
-
-            int childWidthSpec;
-            final int horizontalMargin = lp.leftMargin + lp.rightMargin;
-            if (lp.width == LayoutParams.WRAP_CONTENT) {
-                childWidthSpec = MeasureSpec.makeMeasureSpec(widthAvailable - horizontalMargin,
-                        MeasureSpec.AT_MOST);
-            } else if (lp.width == LayoutParams.MATCH_PARENT) {
-                childWidthSpec = MeasureSpec.makeMeasureSpec(widthAvailable - horizontalMargin,
-                        MeasureSpec.EXACTLY);
-            } else {
-                childWidthSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY);
-            }
-
-            int childHeightSpec;
-            if (lp.height == LayoutParams.WRAP_CONTENT) {
-                childHeightSpec = MeasureSpec.makeMeasureSpec(maxLayoutHeight, MeasureSpec.AT_MOST);
-            } else if (lp.height == LayoutParams.MATCH_PARENT) {
-                childHeightSpec = MeasureSpec.makeMeasureSpec(maxLayoutHeight, MeasureSpec.EXACTLY);
-            } else {
-                childHeightSpec = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY);
-            }
-
-            child.measure(childWidthSpec, childHeightSpec);
-            final int childWidth = child.getMeasuredWidth();
-            final int childHeight = child.getMeasuredHeight();
-
-            if (heightMode == MeasureSpec.AT_MOST && childHeight > layoutHeight) {
-                layoutHeight = Math.min(childHeight, maxLayoutHeight);
-            }
-
-            widthRemaining -= childWidth;
-            canSlide |= lp.slideable = widthRemaining < 0;
-            if (lp.slideable) {
-                mSlideableView = child;
-            }
-        }
-
-        // Resolve weight and make sure non-sliding panels are smaller than the full screen.
-        if (canSlide || weightSum > 0) {
-            final int fixedPanelWidthLimit = widthAvailable - mOverhangSize;
-
-            for (int i = 0; i < childCount; i++) {
-                final View child = getChildAt(i);
-
-                if (child.getVisibility() == GONE) {
-                    continue;
-                }
-
-                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-
-                if (child.getVisibility() == GONE) {
-                    continue;
-                }
-
-                final boolean skippedFirstPass = lp.width == 0 && lp.weight > 0;
-                final int measuredWidth = skippedFirstPass ? 0 : child.getMeasuredWidth();
-                if (canSlide && child != mSlideableView) {
-                    if (lp.width < 0 && (measuredWidth > fixedPanelWidthLimit || lp.weight > 0)) {
-                        // Fixed panels in a sliding configuration should
-                        // be clamped to the fixed panel limit.
-                        final int childHeightSpec;
-                        if (skippedFirstPass) {
-                            // Do initial height measurement if we skipped measuring this view
-                            // the first time around.
-                            if (lp.height == LayoutParams.WRAP_CONTENT) {
-                                childHeightSpec = MeasureSpec.makeMeasureSpec(maxLayoutHeight,
-                                        MeasureSpec.AT_MOST);
-                            } else if (lp.height == LayoutParams.MATCH_PARENT) {
-                                childHeightSpec = MeasureSpec.makeMeasureSpec(maxLayoutHeight,
-                                        MeasureSpec.EXACTLY);
-                            } else {
-                                childHeightSpec = MeasureSpec.makeMeasureSpec(lp.height,
-                                        MeasureSpec.EXACTLY);
-                            }
-                        } else {
-                            childHeightSpec = MeasureSpec.makeMeasureSpec(
-                                    child.getMeasuredHeight(), MeasureSpec.EXACTLY);
-                        }
-                        final int childWidthSpec = MeasureSpec.makeMeasureSpec(
-                                fixedPanelWidthLimit, MeasureSpec.EXACTLY);
-                        child.measure(childWidthSpec, childHeightSpec);
-                    }
-                } else if (lp.weight > 0) {
-                    int childHeightSpec;
-                    if (lp.width == 0) {
-                        // This was skipped the first time; figure out a real height spec.
-                        if (lp.height == LayoutParams.WRAP_CONTENT) {
-                            childHeightSpec = MeasureSpec.makeMeasureSpec(maxLayoutHeight,
-                                    MeasureSpec.AT_MOST);
-                        } else if (lp.height == LayoutParams.MATCH_PARENT) {
-                            childHeightSpec = MeasureSpec.makeMeasureSpec(maxLayoutHeight,
-                                    MeasureSpec.EXACTLY);
-                        } else {
-                            childHeightSpec = MeasureSpec.makeMeasureSpec(lp.height,
-                                    MeasureSpec.EXACTLY);
-                        }
-                    } else {
-                        childHeightSpec = MeasureSpec.makeMeasureSpec(
-                                child.getMeasuredHeight(), MeasureSpec.EXACTLY);
-                    }
-
-                    if (canSlide) {
-                        // Consume available space
-                        final int horizontalMargin = lp.leftMargin + lp.rightMargin;
-                        final int newWidth = widthAvailable - horizontalMargin;
-                        final int childWidthSpec = MeasureSpec.makeMeasureSpec(
-                                newWidth, MeasureSpec.EXACTLY);
-                        if (measuredWidth != newWidth) {
-                            child.measure(childWidthSpec, childHeightSpec);
-                        }
-                    } else {
-                        // Distribute the extra width proportionally similar to LinearLayout
-                        final int widthToDistribute = Math.max(0, widthRemaining);
-                        final int addedWidth = (int) (lp.weight * widthToDistribute / weightSum);
-                        final int childWidthSpec = MeasureSpec.makeMeasureSpec(
-                                measuredWidth + addedWidth, MeasureSpec.EXACTLY);
-                        child.measure(childWidthSpec, childHeightSpec);
-                    }
-                }
-            }
-        }
-
-        final int measuredWidth = widthSize;
-        final int measuredHeight = layoutHeight + getPaddingTop() + getPaddingBottom();
-
-        setMeasuredDimension(measuredWidth, measuredHeight);
-        mCanSlide = canSlide;
-
-        if (mDragHelper.getViewDragState() != ViewDragHelper.STATE_IDLE && !canSlide) {
-            // Cancel scrolling in progress, it's no longer relevant.
-            mDragHelper.abort();
-        }
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int l, int t, int r, int b) {
-        final boolean isLayoutRtl = isLayoutRtlSupport();
-        if (isLayoutRtl) {
-            mDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_RIGHT);
-        } else {
-            mDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);
-        }
-        final int width = r - l;
-        final int paddingStart = isLayoutRtl ? getPaddingRight() : getPaddingLeft();
-        final int paddingEnd = isLayoutRtl ? getPaddingLeft() : getPaddingRight();
-        final int paddingTop = getPaddingTop();
-
-        final int childCount = getChildCount();
-        int xStart = paddingStart;
-        int nextXStart = xStart;
-
-        if (mFirstLayout) {
-            mSlideOffset = mCanSlide && mPreservedOpenState ? 1.f : 0.f;
-        }
-
-        for (int i = 0; i < childCount; i++) {
-            final View child = getChildAt(i);
-
-            if (child.getVisibility() == GONE) {
-                continue;
-            }
-
-            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-
-            final int childWidth = child.getMeasuredWidth();
-            int offset = 0;
-
-            if (lp.slideable) {
-                final int margin = lp.leftMargin + lp.rightMargin;
-                final int range = Math.min(nextXStart,
-                        width - paddingEnd - mOverhangSize) - xStart - margin;
-                mSlideRange = range;
-                final int lpMargin = isLayoutRtl ? lp.rightMargin : lp.leftMargin;
-                lp.dimWhenOffset = xStart + lpMargin + range + childWidth / 2 > width - paddingEnd;
-                final int pos = (int) (range * mSlideOffset);
-                xStart += pos + lpMargin;
-                mSlideOffset = (float) pos / mSlideRange;
-            } else if (mCanSlide && mParallaxBy != 0) {
-                offset = (int) ((1 - mSlideOffset) * mParallaxBy);
-                xStart = nextXStart;
-            } else {
-                xStart = nextXStart;
-            }
-
-            final int childRight;
-            final int childLeft;
-            if (isLayoutRtl) {
-                childRight = width - xStart + offset;
-                childLeft = childRight - childWidth;
-            } else {
-                childLeft = xStart - offset;
-                childRight = childLeft + childWidth;
-            }
-
-            final int childTop = paddingTop;
-            final int childBottom = childTop + child.getMeasuredHeight();
-            child.layout(childLeft, paddingTop, childRight, childBottom);
-
-            nextXStart += child.getWidth();
-        }
-
-        if (mFirstLayout) {
-            if (mCanSlide) {
-                if (mParallaxBy != 0) {
-                    parallaxOtherViews(mSlideOffset);
-                }
-                if (((LayoutParams) mSlideableView.getLayoutParams()).dimWhenOffset) {
-                    dimChildView(mSlideableView, mSlideOffset, mSliderFadeColor);
-                }
-            } else {
-                // Reset the dim level of all children; it's irrelevant when nothing moves.
-                for (int i = 0; i < childCount; i++) {
-                    dimChildView(getChildAt(i), 0, mSliderFadeColor);
-                }
-            }
-            updateObscuredViewsVisibility(mSlideableView);
-        }
-
-        mFirstLayout = false;
-    }
-
-    @Override
-    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-        super.onSizeChanged(w, h, oldw, oldh);
-        // Recalculate sliding panes and their details
-        if (w != oldw) {
-            mFirstLayout = true;
-        }
-    }
-
-    @Override
-    public void requestChildFocus(View child, View focused) {
-        super.requestChildFocus(child, focused);
-        if (!isInTouchMode() && !mCanSlide) {
-            mPreservedOpenState = child == mSlideableView;
-        }
-    }
-
-    @Override
-    public boolean onInterceptTouchEvent(MotionEvent ev) {
-        final int action = ev.getActionMasked();
-
-        // Preserve the open state based on the last view that was touched.
-        if (!mCanSlide && action == MotionEvent.ACTION_DOWN && getChildCount() > 1) {
-            // After the first things will be slideable.
-            final View secondChild = getChildAt(1);
-            if (secondChild != null) {
-                mPreservedOpenState = !mDragHelper.isViewUnder(secondChild,
-                        (int) ev.getX(), (int) ev.getY());
-            }
-        }
-
-        if (!mCanSlide || (mIsUnableToDrag && action != MotionEvent.ACTION_DOWN)) {
-            mDragHelper.cancel();
-            return super.onInterceptTouchEvent(ev);
-        }
-
-        if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
-            mDragHelper.cancel();
-            return false;
-        }
-
-        boolean interceptTap = false;
-
-        switch (action) {
-            case MotionEvent.ACTION_DOWN: {
-                mIsUnableToDrag = false;
-                final float x = ev.getX();
-                final float y = ev.getY();
-                mInitialMotionX = x;
-                mInitialMotionY = y;
-
-                if (mDragHelper.isViewUnder(mSlideableView, (int) x, (int) y)
-                        && isDimmed(mSlideableView)) {
-                    interceptTap = true;
-                }
-                break;
-            }
-
-            case MotionEvent.ACTION_MOVE: {
-                final float x = ev.getX();
-                final float y = ev.getY();
-                final float adx = Math.abs(x - mInitialMotionX);
-                final float ady = Math.abs(y - mInitialMotionY);
-                final int slop = mDragHelper.getTouchSlop();
-                if (adx > slop && ady > adx) {
-                    mDragHelper.cancel();
-                    mIsUnableToDrag = true;
-                    return false;
-                }
-            }
-        }
-
-        final boolean interceptForDrag = mDragHelper.shouldInterceptTouchEvent(ev);
-
-        return interceptForDrag || interceptTap;
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev) {
-        if (!mCanSlide) {
-            return super.onTouchEvent(ev);
-        }
-
-        mDragHelper.processTouchEvent(ev);
-
-        boolean wantTouchEvents = true;
-
-        switch (ev.getActionMasked()) {
-            case MotionEvent.ACTION_DOWN: {
-                final float x = ev.getX();
-                final float y = ev.getY();
-                mInitialMotionX = x;
-                mInitialMotionY = y;
-                break;
-            }
-
-            case MotionEvent.ACTION_UP: {
-                if (isDimmed(mSlideableView)) {
-                    final float x = ev.getX();
-                    final float y = ev.getY();
-                    final float dx = x - mInitialMotionX;
-                    final float dy = y - mInitialMotionY;
-                    final int slop = mDragHelper.getTouchSlop();
-                    if (dx * dx + dy * dy < slop * slop
-                            && mDragHelper.isViewUnder(mSlideableView, (int) x, (int) y)) {
-                        // Taps close a dimmed open pane.
-                        closePane(mSlideableView, 0);
-                        break;
-                    }
-                }
-                break;
-            }
-        }
-
-        return wantTouchEvents;
-    }
-
-    private boolean closePane(View pane, int initialVelocity) {
-        if (mFirstLayout || smoothSlideTo(0.f, initialVelocity)) {
-            mPreservedOpenState = false;
-            return true;
-        }
-        return false;
-    }
-
-    private boolean openPane(View pane, int initialVelocity) {
-        if (mFirstLayout || smoothSlideTo(1.f, initialVelocity)) {
-            mPreservedOpenState = true;
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * @deprecated Renamed to {@link #openPane()} - this method is going away soon!
-     */
-    @Deprecated
-    public void smoothSlideOpen() {
-        openPane();
-    }
-
-    /**
-     * Open the sliding pane if it is currently slideable. If first layout
-     * has already completed this will animate.
-     *
-     * @return true if the pane was slideable and is now open/in the process of opening
-     */
-    public boolean openPane() {
-        return openPane(mSlideableView, 0);
-    }
-
-    /**
-     * @deprecated Renamed to {@link #closePane()} - this method is going away soon!
-     */
-    @Deprecated
-    public void smoothSlideClosed() {
-        closePane();
-    }
-
-    /**
-     * Close the sliding pane if it is currently slideable. If first layout
-     * has already completed this will animate.
-     *
-     * @return true if the pane was slideable and is now closed/in the process of closing
-     */
-    public boolean closePane() {
-        return closePane(mSlideableView, 0);
-    }
-
-    /**
-     * Check if the layout is completely open. It can be open either because the slider
-     * itself is open revealing the left pane, or if all content fits without sliding.
-     *
-     * @return true if sliding panels are completely open
-     */
-    public boolean isOpen() {
-        return !mCanSlide || mSlideOffset == 1;
-    }
-
-    /**
-     * @return true if content in this layout can be slid open and closed
-     * @deprecated Renamed to {@link #isSlideable()} - this method is going away soon!
-     */
-    @Deprecated
-    public boolean canSlide() {
-        return mCanSlide;
-    }
-
-    /**
-     * Check if the content in this layout cannot fully fit side by side and therefore
-     * the content pane can be slid back and forth.
-     *
-     * @return true if content in this layout can be slid open and closed
-     */
-    public boolean isSlideable() {
-        return mCanSlide;
-    }
-
-    void onPanelDragged(int newLeft) {
-        if (mSlideableView == null) {
-            // This can happen if we're aborting motion during layout because everything now fits.
-            mSlideOffset = 0;
-            return;
-        }
-        final boolean isLayoutRtl = isLayoutRtlSupport();
-        final LayoutParams lp = (LayoutParams) mSlideableView.getLayoutParams();
-
-        int childWidth = mSlideableView.getWidth();
-        final int newStart = isLayoutRtl ? getWidth() - newLeft - childWidth : newLeft;
-
-        final int paddingStart = isLayoutRtl ? getPaddingRight() : getPaddingLeft();
-        final int lpMargin = isLayoutRtl ? lp.rightMargin : lp.leftMargin;
-        final int startBound = paddingStart + lpMargin;
-
-        mSlideOffset = (float) (newStart - startBound) / mSlideRange;
-
-        if (mParallaxBy != 0) {
-            parallaxOtherViews(mSlideOffset);
-        }
-
-        if (lp.dimWhenOffset) {
-            dimChildView(mSlideableView, mSlideOffset, mSliderFadeColor);
-        }
-        dispatchOnPanelSlide(mSlideableView);
-    }
-
-    private void dimChildView(View v, float mag, int fadeColor) {
-        final LayoutParams lp = (LayoutParams) v.getLayoutParams();
-
-        if (mag > 0 && fadeColor != 0) {
-            final int baseAlpha = (fadeColor & 0xff000000) >>> 24;
-            int imag = (int) (baseAlpha * mag);
-            int color = imag << 24 | (fadeColor & 0xffffff);
-            if (lp.dimPaint == null) {
-                lp.dimPaint = new Paint();
-            }
-            lp.dimPaint.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_OVER));
-            if (v.getLayerType() != View.LAYER_TYPE_HARDWARE) {
-                v.setLayerType(View.LAYER_TYPE_HARDWARE, lp.dimPaint);
-            }
-            invalidateChildRegion(v);
-        } else if (v.getLayerType() != View.LAYER_TYPE_NONE) {
-            if (lp.dimPaint != null) {
-                lp.dimPaint.setColorFilter(null);
-            }
-            final DisableLayerRunnable dlr = new DisableLayerRunnable(v);
-            mPostedRunnables.add(dlr);
-            ViewCompat.postOnAnimation(this, dlr);
-        }
-    }
-
-    @Override
-    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
-        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-        boolean result;
-        final int save = canvas.save();
-
-        if (mCanSlide && !lp.slideable && mSlideableView != null) {
-            // Clip against the slider; no sense drawing what will immediately be covered.
-            canvas.getClipBounds(mTmpRect);
-            if (isLayoutRtlSupport()) {
-                mTmpRect.left = Math.max(mTmpRect.left, mSlideableView.getRight());
-            } else {
-                mTmpRect.right = Math.min(mTmpRect.right, mSlideableView.getLeft());
-            }
-            canvas.clipRect(mTmpRect);
-        }
-
-        result = super.drawChild(canvas, child, drawingTime);
-
-        canvas.restoreToCount(save);
-
-        return result;
-    }
-
-    void invalidateChildRegion(View v) {
-        IMPL.invalidateChildRegion(this, v);
-    }
-
-    /**
-     * Smoothly animate mDraggingPane to the target X position within its range.
-     *
-     * @param slideOffset position to animate to
-     * @param velocity initial velocity in case of fling, or 0.
-     */
-    boolean smoothSlideTo(float slideOffset, int velocity) {
-        if (!mCanSlide) {
-            // Nothing to do.
-            return false;
-        }
-
-        final boolean isLayoutRtl = isLayoutRtlSupport();
-        final LayoutParams lp = (LayoutParams) mSlideableView.getLayoutParams();
-
-        int x;
-        if (isLayoutRtl) {
-            int startBound = getPaddingRight() + lp.rightMargin;
-            int childWidth = mSlideableView.getWidth();
-            x = (int) (getWidth() - (startBound + slideOffset * mSlideRange + childWidth));
-        } else {
-            int startBound = getPaddingLeft() + lp.leftMargin;
-            x = (int) (startBound + slideOffset * mSlideRange);
-        }
-
-        if (mDragHelper.smoothSlideViewTo(mSlideableView, x, mSlideableView.getTop())) {
-            setAllChildrenVisible();
-            ViewCompat.postInvalidateOnAnimation(this);
-            return true;
-        }
-        return false;
-    }
-
-    @Override
-    public void computeScroll() {
-        if (mDragHelper.continueSettling(true)) {
-            if (!mCanSlide) {
-                mDragHelper.abort();
-                return;
-            }
-
-            ViewCompat.postInvalidateOnAnimation(this);
-        }
-    }
-
-    /**
-     * @deprecated Renamed to {@link #setShadowDrawableLeft(Drawable d)} to support LTR (left to
-     * right language) and {@link #setShadowDrawableRight(Drawable d)} to support RTL (right to left
-     * language) during opening/closing.
-     *
-     * @param d drawable to use as a shadow
-     */
-    @Deprecated
-    public void setShadowDrawable(Drawable d) {
-        setShadowDrawableLeft(d);
-    }
-
-    /**
-     * Set a drawable to use as a shadow cast by the right pane onto the left pane
-     * during opening/closing.
-     *
-     * @param d drawable to use as a shadow
-     */
-    public void setShadowDrawableLeft(@Nullable Drawable d) {
-        mShadowDrawableLeft = d;
-    }
-
-    /**
-     * Set a drawable to use as a shadow cast by the left pane onto the right pane
-     * during opening/closing to support right to left language.
-     *
-     * @param d drawable to use as a shadow
-     */
-    public void setShadowDrawableRight(@Nullable Drawable d) {
-        mShadowDrawableRight = d;
-    }
-
-    /**
-     * Set a drawable to use as a shadow cast by the right pane onto the left pane
-     * during opening/closing.
-     *
-     * @param resId Resource ID of a drawable to use
-     * @deprecated Renamed to {@link #setShadowResourceLeft(int)} to support LTR (left to
-     * right language) and {@link #setShadowResourceRight(int)} to support RTL (right to left
-     * language) during opening/closing.
-     */
-    @Deprecated
-    public void setShadowResource(@DrawableRes int resId) {
-        setShadowDrawable(getResources().getDrawable(resId));
-    }
-
-    /**
-     * Set a drawable to use as a shadow cast by the right pane onto the left pane
-     * during opening/closing.
-     *
-     * @param resId Resource ID of a drawable to use
-     */
-    public void setShadowResourceLeft(int resId) {
-        setShadowDrawableLeft(ContextCompat.getDrawable(getContext(), resId));
-    }
-
-    /**
-     * Set a drawable to use as a shadow cast by the left pane onto the right pane
-     * during opening/closing to support right to left language.
-     *
-     * @param resId Resource ID of a drawable to use
-     */
-    public void setShadowResourceRight(int resId) {
-        setShadowDrawableRight(ContextCompat.getDrawable(getContext(), resId));
-    }
-
-    @Override
-    public void draw(Canvas c) {
-        super.draw(c);
-        final boolean isLayoutRtl = isLayoutRtlSupport();
-        Drawable shadowDrawable;
-        if (isLayoutRtl) {
-            shadowDrawable = mShadowDrawableRight;
-        } else {
-            shadowDrawable = mShadowDrawableLeft;
-        }
-
-        final View shadowView = getChildCount() > 1 ? getChildAt(1) : null;
-        if (shadowView == null || shadowDrawable == null) {
-            // No need to draw a shadow if we don't have one.
-            return;
-        }
-
-        final int top = shadowView.getTop();
-        final int bottom = shadowView.getBottom();
-
-        final int shadowWidth = shadowDrawable.getIntrinsicWidth();
-        final int left;
-        final int right;
-        if (isLayoutRtlSupport()) {
-            left = shadowView.getRight();
-            right = left + shadowWidth;
-        } else {
-            right = shadowView.getLeft();
-            left = right - shadowWidth;
-        }
-
-        shadowDrawable.setBounds(left, top, right, bottom);
-        shadowDrawable.draw(c);
-    }
-
-    private void parallaxOtherViews(float slideOffset) {
-        final boolean isLayoutRtl = isLayoutRtlSupport();
-        final LayoutParams slideLp = (LayoutParams) mSlideableView.getLayoutParams();
-        final boolean dimViews = slideLp.dimWhenOffset
-                && (isLayoutRtl ? slideLp.rightMargin : slideLp.leftMargin) <= 0;
-        final int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            final View v = getChildAt(i);
-            if (v == mSlideableView) continue;
-
-            final int oldOffset = (int) ((1 - mParallaxOffset) * mParallaxBy);
-            mParallaxOffset = slideOffset;
-            final int newOffset = (int) ((1 - slideOffset) * mParallaxBy);
-            final int dx = oldOffset - newOffset;
-
-            v.offsetLeftAndRight(isLayoutRtl ? -dx : dx);
-
-            if (dimViews) {
-                dimChildView(v, isLayoutRtl ? mParallaxOffset - 1
-                        : 1 - mParallaxOffset, mCoveredFadeColor);
-            }
-        }
-    }
-
-    /**
-     * Tests scrollability within child views of v given a delta of dx.
-     *
-     * @param v View to test for horizontal scrollability
-     * @param checkV Whether the view v passed should itself be checked for scrollability (true),
-     *               or just its children (false).
-     * @param dx Delta scrolled in pixels
-     * @param x X coordinate of the active touch point
-     * @param y Y coordinate of the active touch point
-     * @return true if child views of v can be scrolled by delta of dx.
-     */
-    protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
-        if (v instanceof ViewGroup) {
-            final ViewGroup group = (ViewGroup) v;
-            final int scrollX = v.getScrollX();
-            final int scrollY = v.getScrollY();
-            final int count = group.getChildCount();
-            // Count backwards - let topmost views consume scroll distance first.
-            for (int i = count - 1; i >= 0; i--) {
-                // TODO: Add versioned support here for transformed views.
-                // This will not work for transformed views in Honeycomb+
-                final View child = group.getChildAt(i);
-                if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight()
-                        && y + scrollY >= child.getTop() && y + scrollY < child.getBottom()
-                        && canScroll(child, true, dx, x + scrollX - child.getLeft(),
-                                y + scrollY - child.getTop())) {
-                    return true;
-                }
-            }
-        }
-
-        return checkV && v.canScrollHorizontally((isLayoutRtlSupport() ? dx : -dx));
-    }
-
-    boolean isDimmed(View child) {
-        if (child == null) {
-            return false;
-        }
-        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-        return mCanSlide && lp.dimWhenOffset && mSlideOffset > 0;
-    }
-
-    @Override
-    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
-        return new LayoutParams();
-    }
-
-    @Override
-    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
-        return p instanceof 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
-    protected Parcelable onSaveInstanceState() {
-        Parcelable superState = super.onSaveInstanceState();
-
-        SavedState ss = new SavedState(superState);
-        ss.isOpen = isSlideable() ? isOpen() : mPreservedOpenState;
-
-        return ss;
-    }
-
-    @Override
-    protected void onRestoreInstanceState(Parcelable state) {
-        if (!(state instanceof SavedState)) {
-            super.onRestoreInstanceState(state);
-            return;
-        }
-
-        SavedState ss = (SavedState) state;
-        super.onRestoreInstanceState(ss.getSuperState());
-
-        if (ss.isOpen) {
-            openPane();
-        } else {
-            closePane();
-        }
-        mPreservedOpenState = ss.isOpen;
-    }
-
-    private class DragHelperCallback extends ViewDragHelper.Callback {
-
-        DragHelperCallback() {
-        }
-
-        @Override
-        public boolean tryCaptureView(View child, int pointerId) {
-            if (mIsUnableToDrag) {
-                return false;
-            }
-
-            return ((LayoutParams) child.getLayoutParams()).slideable;
-        }
-
-        @Override
-        public void onViewDragStateChanged(int state) {
-            if (mDragHelper.getViewDragState() == ViewDragHelper.STATE_IDLE) {
-                if (mSlideOffset == 0) {
-                    updateObscuredViewsVisibility(mSlideableView);
-                    dispatchOnPanelClosed(mSlideableView);
-                    mPreservedOpenState = false;
-                } else {
-                    dispatchOnPanelOpened(mSlideableView);
-                    mPreservedOpenState = true;
-                }
-            }
-        }
-
-        @Override
-        public void onViewCaptured(View capturedChild, int activePointerId) {
-            // Make all child views visible in preparation for sliding things around
-            setAllChildrenVisible();
-        }
-
-        @Override
-        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
-            onPanelDragged(left);
-            invalidate();
-        }
-
-        @Override
-        public void onViewReleased(View releasedChild, float xvel, float yvel) {
-            final LayoutParams lp = (LayoutParams) releasedChild.getLayoutParams();
-
-            int left;
-            if (isLayoutRtlSupport()) {
-                int startToRight =  getPaddingRight() + lp.rightMargin;
-                if (xvel < 0 || (xvel == 0 && mSlideOffset > 0.5f)) {
-                    startToRight += mSlideRange;
-                }
-                int childWidth = mSlideableView.getWidth();
-                left = getWidth() - startToRight - childWidth;
-            } else {
-                left = getPaddingLeft() + lp.leftMargin;
-                if (xvel > 0 || (xvel == 0 && mSlideOffset > 0.5f)) {
-                    left += mSlideRange;
-                }
-            }
-            mDragHelper.settleCapturedViewAt(left, releasedChild.getTop());
-            invalidate();
-        }
-
-        @Override
-        public int getViewHorizontalDragRange(View child) {
-            return mSlideRange;
-        }
-
-        @Override
-        public int clampViewPositionHorizontal(View child, int left, int dx) {
-            final LayoutParams lp = (LayoutParams) mSlideableView.getLayoutParams();
-
-            final int newLeft;
-            if (isLayoutRtlSupport()) {
-                int startBound = getWidth()
-                        - (getPaddingRight() + lp.rightMargin + mSlideableView.getWidth());
-                int endBound =  startBound - mSlideRange;
-                newLeft = Math.max(Math.min(left, startBound), endBound);
-            } else {
-                int startBound = getPaddingLeft() + lp.leftMargin;
-                int endBound = startBound + mSlideRange;
-                newLeft = Math.min(Math.max(left, startBound), endBound);
-            }
-            return newLeft;
-        }
-
-        @Override
-        public int clampViewPositionVertical(View child, int top, int dy) {
-            // Make sure we never move views vertically.
-            // This could happen if the child has less height than its parent.
-            return child.getTop();
-        }
-
-        @Override
-        public void onEdgeDragStarted(int edgeFlags, int pointerId) {
-            mDragHelper.captureChildView(mSlideableView, pointerId);
-        }
-    }
-
-    public static class LayoutParams extends ViewGroup.MarginLayoutParams {
-        private static final int[] ATTRS = new int[] {
-            android.R.attr.layout_weight
-        };
-
-        /**
-         * The weighted proportion of how much of the leftover space
-         * this child should consume after measurement.
-         */
-        public float weight = 0;
-
-        /**
-         * True if this pane is the slideable pane in the layout.
-         */
-        boolean slideable;
-
-        /**
-         * True if this view should be drawn dimmed
-         * when it's been offset from its default position.
-         */
-        boolean dimWhenOffset;
-
-        Paint dimPaint;
-
-        public LayoutParams() {
-            super(MATCH_PARENT, MATCH_PARENT);
-        }
-
-        public LayoutParams(int width, int height) {
-            super(width, height);
-        }
-
-        public LayoutParams(@NonNull android.view.ViewGroup.LayoutParams source) {
-            super(source);
-        }
-
-        public LayoutParams(@NonNull MarginLayoutParams source) {
-            super(source);
-        }
-
-        public LayoutParams(@NonNull LayoutParams source) {
-            super(source);
-            this.weight = source.weight;
-        }
-
-        public LayoutParams(@NonNull Context c, @Nullable AttributeSet attrs) {
-            super(c, attrs);
-
-            final TypedArray a = c.obtainStyledAttributes(attrs, ATTRS);
-            this.weight = a.getFloat(0, 0);
-            a.recycle();
-        }
-
-    }
-
-    static class SavedState extends AbsSavedState {
-        boolean isOpen;
-
-        SavedState(Parcelable superState) {
-            super(superState);
-        }
-
-        SavedState(Parcel in, ClassLoader loader) {
-            super(in, loader);
-            isOpen = in.readInt() != 0;
-        }
-
-        @Override
-        public void writeToParcel(Parcel out, int flags) {
-            super.writeToParcel(out, flags);
-            out.writeInt(isOpen ? 1 : 0);
-        }
-
-        public static final Creator<SavedState> CREATOR = new ClassLoaderCreator<SavedState>() {
-            @Override
-            public SavedState createFromParcel(Parcel in, ClassLoader loader) {
-                return new SavedState(in, null);
-            }
-
-            @Override
-            public SavedState createFromParcel(Parcel in) {
-                return new SavedState(in, null);
-            }
-
-            @Override
-            public SavedState[] newArray(int size) {
-                return new SavedState[size];
-            }
-        };
-    }
-
-    interface SlidingPanelLayoutImpl {
-        void invalidateChildRegion(SlidingPaneLayout parent, View child);
-    }
-
-    static class SlidingPanelLayoutImplBase implements SlidingPanelLayoutImpl {
-        @Override
-        public void invalidateChildRegion(SlidingPaneLayout parent, View child) {
-            ViewCompat.postInvalidateOnAnimation(parent, child.getLeft(), child.getTop(),
-                    child.getRight(), child.getBottom());
-        }
-    }
-
-    @RequiresApi(16)
-    static class SlidingPanelLayoutImplJB extends SlidingPanelLayoutImplBase {
-        /*
-         * Private API hacks! Nasty! Bad!
-         *
-         * In Jellybean, some optimizations in the hardware UI renderer
-         * prevent a changed Paint on a View using a hardware layer from having
-         * the intended effect. This twiddles some internal bits on the view to force
-         * it to recreate the display list.
-         */
-        private Method mGetDisplayList;
-        private Field mRecreateDisplayList;
-
-        SlidingPanelLayoutImplJB() {
-            try {
-                mGetDisplayList = View.class.getDeclaredMethod("getDisplayList", (Class[]) null);
-            } catch (NoSuchMethodException e) {
-                Log.e(TAG, "Couldn't fetch getDisplayList method; dimming won't work right.", e);
-            }
-            try {
-                mRecreateDisplayList = View.class.getDeclaredField("mRecreateDisplayList");
-                mRecreateDisplayList.setAccessible(true);
-            } catch (NoSuchFieldException e) {
-                Log.e(TAG, "Couldn't fetch mRecreateDisplayList field; dimming will be slow.", e);
-            }
-        }
-
-        @Override
-        public void invalidateChildRegion(SlidingPaneLayout parent, View child) {
-            if (mGetDisplayList != null && mRecreateDisplayList != null) {
-                try {
-                    mRecreateDisplayList.setBoolean(child, true);
-                    mGetDisplayList.invoke(child, (Object[]) null);
-                } catch (Exception e) {
-                    Log.e(TAG, "Error refreshing display list state", e);
-                }
-            } else {
-                // Slow path. REALLY slow path. Let's hope we don't get here.
-                child.invalidate();
-                return;
-            }
-            super.invalidateChildRegion(parent, child);
-        }
-    }
-
-    @RequiresApi(17)
-    static class SlidingPanelLayoutImplJBMR1 extends SlidingPanelLayoutImplBase {
-        @Override
-        public void invalidateChildRegion(SlidingPaneLayout parent, View child) {
-            ViewCompat.setLayerPaint(child, ((LayoutParams) child.getLayoutParams()).dimPaint);
-        }
-    }
-
-    class AccessibilityDelegate extends AccessibilityDelegateCompat {
-        private final Rect mTmpRect = new Rect();
-
-        @Override
-        public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
-            final AccessibilityNodeInfoCompat superNode = AccessibilityNodeInfoCompat.obtain(info);
-            super.onInitializeAccessibilityNodeInfo(host, superNode);
-            copyNodeInfoNoChildren(info, superNode);
-            superNode.recycle();
-
-            info.setClassName(SlidingPaneLayout.class.getName());
-            info.setSource(host);
-
-            final ViewParent parent = ViewCompat.getParentForAccessibility(host);
-            if (parent instanceof View) {
-                info.setParent((View) parent);
-            }
-
-            // This is a best-approximation of addChildrenForAccessibility()
-            // that accounts for filtering.
-            final int childCount = getChildCount();
-            for (int i = 0; i < childCount; i++) {
-                final View child = getChildAt(i);
-                if (!filter(child) && (child.getVisibility() == View.VISIBLE)) {
-                    // Force importance to "yes" since we can't read the value.
-                    ViewCompat.setImportantForAccessibility(
-                            child, ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
-                    info.addChild(child);
-                }
-            }
-        }
-
-        @Override
-        public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
-            super.onInitializeAccessibilityEvent(host, event);
-
-            event.setClassName(SlidingPaneLayout.class.getName());
-        }
-
-        @Override
-        public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child,
-                AccessibilityEvent event) {
-            if (!filter(child)) {
-                return super.onRequestSendAccessibilityEvent(host, child, event);
-            }
-            return false;
-        }
-
-        public boolean filter(View child) {
-            return isDimmed(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());
-
-            dest.setMovementGranularities(src.getMovementGranularities());
-        }
-    }
-
-    private class DisableLayerRunnable implements Runnable {
-        final View mChildView;
-
-        DisableLayerRunnable(View childView) {
-            mChildView = childView;
-        }
-
-        @Override
-        public void run() {
-            if (mChildView.getParent() == SlidingPaneLayout.this) {
-                mChildView.setLayerType(View.LAYER_TYPE_NONE, null);
-                invalidateChildRegion(mChildView);
-            }
-            mPostedRunnables.remove(this);
-        }
-    }
-
-    boolean isLayoutRtlSupport() {
-        return ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_RTL;
-    }
-}
diff --git a/core-ui/src/main/java/android/support/v4/widget/ViewDragHelper.java b/core-ui/src/main/java/android/support/v4/widget/ViewDragHelper.java
deleted file mode 100644
index 09c6f66..0000000
--- a/core-ui/src/main/java/android/support/v4/widget/ViewDragHelper.java
+++ /dev/null
@@ -1,1514 +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.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v4.view.ViewCompat;
-import android.util.Log;
-import android.view.MotionEvent;
-import android.view.VelocityTracker;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewGroup;
-import android.view.animation.Interpolator;
-import android.widget.OverScroller;
-
-import java.util.Arrays;
-
-/**
- * ViewDragHelper is a utility class for writing custom ViewGroups. It offers a number
- * of useful operations and state tracking for allowing a user to drag and reposition
- * views within their parent ViewGroup.
- */
-public class ViewDragHelper {
-    private static final String TAG = "ViewDragHelper";
-
-    /**
-     * A null/invalid pointer ID.
-     */
-    public static final int INVALID_POINTER = -1;
-
-    /**
-     * A view is not currently being dragged or animating as a result of a fling/snap.
-     */
-    public static final int STATE_IDLE = 0;
-
-    /**
-     * 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 = 1;
-
-    /**
-     * A view is currently settling into place as a result of a fling or
-     * predefined non-interactive motion.
-     */
-    public static final int STATE_SETTLING = 2;
-
-    /**
-     * Edge flag indicating that the left edge should be affected.
-     */
-    public static final int EDGE_LEFT = 1 << 0;
-
-    /**
-     * Edge flag indicating that the right edge should be affected.
-     */
-    public static final int EDGE_RIGHT = 1 << 1;
-
-    /**
-     * Edge flag indicating that the top edge should be affected.
-     */
-    public static final int EDGE_TOP = 1 << 2;
-
-    /**
-     * Edge flag indicating that the bottom edge should be affected.
-     */
-    public static final int EDGE_BOTTOM = 1 << 3;
-
-    /**
-     * Edge flag set indicating all edges should be affected.
-     */
-    public static final int EDGE_ALL = EDGE_LEFT | EDGE_TOP | EDGE_RIGHT | EDGE_BOTTOM;
-
-    /**
-     * Indicates that a check should occur along the horizontal axis
-     */
-    public static final int DIRECTION_HORIZONTAL = 1 << 0;
-
-    /**
-     * Indicates that a check should occur along the vertical axis
-     */
-    public static final int DIRECTION_VERTICAL = 1 << 1;
-
-    /**
-     * Indicates that a check should occur along all axes
-     */
-    public static final int DIRECTION_ALL = DIRECTION_HORIZONTAL | DIRECTION_VERTICAL;
-
-    private static final int EDGE_SIZE = 20; // dp
-
-    private static final int BASE_SETTLE_DURATION = 256; // ms
-    private static final int MAX_SETTLE_DURATION = 600; // ms
-
-    // Current drag state; idle, dragging or settling
-    private int mDragState;
-
-    // Distance to travel before a drag may begin
-    private int mTouchSlop;
-
-    // Last known position/pointer tracking
-    private int mActivePointerId = INVALID_POINTER;
-    private float[] mInitialMotionX;
-    private float[] mInitialMotionY;
-    private float[] mLastMotionX;
-    private float[] mLastMotionY;
-    private int[] mInitialEdgesTouched;
-    private int[] mEdgeDragsInProgress;
-    private int[] mEdgeDragsLocked;
-    private int mPointersDown;
-
-    private VelocityTracker mVelocityTracker;
-    private float mMaxVelocity;
-    private float mMinVelocity;
-
-    private int mEdgeSize;
-    private int mTrackingEdges;
-
-    private OverScroller mScroller;
-
-    private final Callback mCallback;
-
-    private View mCapturedView;
-    private boolean mReleaseInProgress;
-
-    private final ViewGroup mParentView;
-
-    /**
-     * A Callback is used as a communication channel with the ViewDragHelper back to the
-     * parent view using it. <code>on*</code>methods are invoked on siginficant events and several
-     * accessor methods are expected to provide the ViewDragHelper with more information
-     * about the state of the parent view upon request. The callback also makes decisions
-     * governing the range and draggability of child views.
-     */
-    public abstract static class Callback {
-        /**
-         * Called when the drag state changes. See the <code>STATE_*</code> constants
-         * for more information.
-         *
-         * @param state The new drag state
-         *
-         * @see #STATE_IDLE
-         * @see #STATE_DRAGGING
-         * @see #STATE_SETTLING
-         */
-        public void onViewDragStateChanged(int state) {}
-
-        /**
-         * Called when the captured view's position changes as the result of a drag or settle.
-         *
-         * @param changedView View whose position changed
-         * @param left New X coordinate of the left edge of the view
-         * @param top New Y coordinate of the top edge of the view
-         * @param dx Change in X position from the last call
-         * @param dy Change in Y position from the last call
-         */
-        public void onViewPositionChanged(@NonNull View changedView, int left, int top, int dx,
-                int dy) {
-        }
-
-        /**
-         * Called when a child view is captured for dragging or settling. The ID of the pointer
-         * currently dragging the captured view is supplied. If activePointerId is
-         * identified as {@link #INVALID_POINTER} the capture is programmatic instead of
-         * pointer-initiated.
-         *
-         * @param capturedChild Child view that was captured
-         * @param activePointerId Pointer id tracking the child capture
-         */
-        public void onViewCaptured(@NonNull View capturedChild, int activePointerId) {}
-
-        /**
-         * Called when the child view is no longer being actively dragged.
-         * The fling velocity is also supplied, if relevant. The velocity values may
-         * be clamped to system minimums or maximums.
-         *
-         * <p>Calling code may decide to fling or otherwise release the view to let it
-         * settle into place. It should do so using {@link #settleCapturedViewAt(int, int)}
-         * or {@link #flingCapturedView(int, int, int, int)}. If the Callback invokes
-         * one of these methods, the ViewDragHelper will enter {@link #STATE_SETTLING}
-         * and the view capture will not fully end until it comes to a complete stop.
-         * If neither of these methods is invoked before <code>onViewReleased</code> returns,
-         * the view will stop in place and the ViewDragHelper will return to
-         * {@link #STATE_IDLE}.</p>
-         *
-         * @param releasedChild The captured child view now being released
-         * @param xvel X velocity of the pointer as it left the screen in pixels per second.
-         * @param yvel Y velocity of the pointer as it left the screen in pixels per second.
-         */
-        public void onViewReleased(@NonNull View releasedChild, float xvel, float yvel) {}
-
-        /**
-         * Called when one of the subscribed edges in the parent view has been touched
-         * by the user while no child view is currently captured.
-         *
-         * @param edgeFlags A combination of edge flags describing the edge(s) currently touched
-         * @param pointerId ID of the pointer touching the described edge(s)
-         * @see #EDGE_LEFT
-         * @see #EDGE_TOP
-         * @see #EDGE_RIGHT
-         * @see #EDGE_BOTTOM
-         */
-        public void onEdgeTouched(int edgeFlags, int pointerId) {}
-
-        /**
-         * Called when the given edge may become locked. This can happen if an edge drag
-         * was preliminarily rejected before beginning, but after {@link #onEdgeTouched(int, int)}
-         * was called. This method should return true to lock this edge or false to leave it
-         * unlocked. The default behavior is to leave edges unlocked.
-         *
-         * @param edgeFlags A combination of edge flags describing the edge(s) locked
-         * @return true to lock the edge, false to leave it unlocked
-         */
-        public boolean onEdgeLock(int edgeFlags) {
-            return false;
-        }
-
-        /**
-         * Called when the user has started a deliberate drag away from one
-         * of the subscribed edges in the parent view while no child view is currently captured.
-         *
-         * @param edgeFlags A combination of edge flags describing the edge(s) dragged
-         * @param pointerId ID of the pointer touching the described edge(s)
-         * @see #EDGE_LEFT
-         * @see #EDGE_TOP
-         * @see #EDGE_RIGHT
-         * @see #EDGE_BOTTOM
-         */
-        public void onEdgeDragStarted(int edgeFlags, int pointerId) {}
-
-        /**
-         * Called to determine the Z-order of child views.
-         *
-         * @param index the ordered position to query for
-         * @return index of the view that should be ordered at position <code>index</code>
-         */
-        public int getOrderedChildIndex(int index) {
-            return index;
-        }
-
-        /**
-         * Return the magnitude of a draggable child view's horizontal range of motion in pixels.
-         * This method should return 0 for views that cannot move horizontally.
-         *
-         * @param child Child view to check
-         * @return range of horizontal motion in pixels
-         */
-        public int getViewHorizontalDragRange(@NonNull View child) {
-            return 0;
-        }
-
-        /**
-         * Return the magnitude of a draggable child view's vertical range of motion in pixels.
-         * This method should return 0 for views that cannot move vertically.
-         *
-         * @param child Child view to check
-         * @return range of vertical motion in pixels
-         */
-        public int getViewVerticalDragRange(@NonNull View child) {
-            return 0;
-        }
-
-        /**
-         * Called when the user's input indicates that they want to capture the given child view
-         * with the pointer indicated by pointerId. The callback should return true if the user
-         * is permitted to drag the given view with the indicated pointer.
-         *
-         * <p>ViewDragHelper may call this method multiple times for the same view even if
-         * the view is already captured; this indicates that a new pointer is trying to take
-         * control of the view.</p>
-         *
-         * <p>If this method returns true, a call to {@link #onViewCaptured(android.view.View, int)}
-         * will follow if the capture is successful.</p>
-         *
-         * @param child Child the user is attempting to capture
-         * @param pointerId ID of the pointer attempting the capture
-         * @return true if capture should be allowed, false otherwise
-         */
-        public abstract boolean tryCaptureView(@NonNull View child, int pointerId);
-
-        /**
-         * Restrict the motion of the dragged child view along the horizontal axis.
-         * The default implementation does not allow horizontal motion; the extending
-         * class must override this method and provide the desired clamping.
-         *
-         *
-         * @param child Child view being dragged
-         * @param left Attempted motion along the X axis
-         * @param dx Proposed change in position for left
-         * @return The new clamped position for left
-         */
-        public int clampViewPositionHorizontal(@NonNull View child, int left, int dx) {
-            return 0;
-        }
-
-        /**
-         * Restrict the motion of the dragged child view along the vertical axis.
-         * The default implementation does not allow vertical motion; the extending
-         * class must override this method and provide the desired clamping.
-         *
-         *
-         * @param child Child view being dragged
-         * @param top Attempted motion along the Y axis
-         * @param dy Proposed change in position for top
-         * @return The new clamped position for top
-         */
-        public int clampViewPositionVertical(@NonNull View child, int top, int dy) {
-            return 0;
-        }
-    }
-
-    /**
-     * Interpolator defining the animation curve for mScroller
-     */
-    private static final Interpolator sInterpolator = new Interpolator() {
-        @Override
-        public float getInterpolation(float t) {
-            t -= 1.0f;
-            return t * t * t * t * t + 1.0f;
-        }
-    };
-
-    private final Runnable mSetIdleRunnable = new Runnable() {
-        @Override
-        public void run() {
-            setDragState(STATE_IDLE);
-        }
-    };
-
-    /**
-     * Factory method to create a new ViewDragHelper.
-     *
-     * @param forParent Parent view to monitor
-     * @param cb Callback to provide information and receive events
-     * @return a new ViewDragHelper instance
-     */
-    public static ViewDragHelper create(@NonNull ViewGroup forParent, @NonNull Callback cb) {
-        return new ViewDragHelper(forParent.getContext(), forParent, cb);
-    }
-
-    /**
-     * Factory method to create a new ViewDragHelper.
-     *
-     * @param forParent Parent view to monitor
-     * @param sensitivity Multiplier for how sensitive the helper should be about detecting
-     *                    the start of a drag. Larger values are more sensitive. 1.0f is normal.
-     * @param cb Callback to provide information and receive events
-     * @return a new ViewDragHelper instance
-     */
-    public static ViewDragHelper create(@NonNull ViewGroup forParent, float sensitivity,
-            @NonNull Callback cb) {
-        final ViewDragHelper helper = create(forParent, cb);
-        helper.mTouchSlop = (int) (helper.mTouchSlop * (1 / sensitivity));
-        return helper;
-    }
-
-    /**
-     * Apps should use ViewDragHelper.create() to get a new instance.
-     * This will allow VDH to use internal compatibility implementations for different
-     * platform versions.
-     *
-     * @param context Context to initialize config-dependent params from
-     * @param forParent Parent view to monitor
-     */
-    private ViewDragHelper(@NonNull Context context, @NonNull ViewGroup forParent,
-            @NonNull Callback cb) {
-        if (forParent == null) {
-            throw new IllegalArgumentException("Parent view may not be null");
-        }
-        if (cb == null) {
-            throw new IllegalArgumentException("Callback may not be null");
-        }
-
-        mParentView = forParent;
-        mCallback = cb;
-
-        final ViewConfiguration vc = ViewConfiguration.get(context);
-        final float density = context.getResources().getDisplayMetrics().density;
-        mEdgeSize = (int) (EDGE_SIZE * density + 0.5f);
-
-        mTouchSlop = vc.getScaledTouchSlop();
-        mMaxVelocity = vc.getScaledMaximumFlingVelocity();
-        mMinVelocity = vc.getScaledMinimumFlingVelocity();
-        mScroller = new OverScroller(context, sInterpolator);
-    }
-
-    /**
-     * Set the minimum velocity that will be detected as having a magnitude greater than zero
-     * in pixels per second. Callback methods accepting a velocity will be clamped appropriately.
-     *
-     * @param minVel Minimum velocity to detect
-     */
-    public void setMinVelocity(float minVel) {
-        mMinVelocity = minVel;
-    }
-
-    /**
-     * Return the currently configured minimum velocity. Any flings with a magnitude less
-     * than this value in pixels per second. Callback methods accepting a velocity will receive
-     * zero as a velocity value if the real detected velocity was below this threshold.
-     *
-     * @return the minimum velocity that will be detected
-     */
-    public float getMinVelocity() {
-        return mMinVelocity;
-    }
-
-    /**
-     * Retrieve the current drag state of this helper. This will return one of
-     * {@link #STATE_IDLE}, {@link #STATE_DRAGGING} or {@link #STATE_SETTLING}.
-     * @return The current drag state
-     */
-    public int getViewDragState() {
-        return mDragState;
-    }
-
-    /**
-     * Enable edge tracking for the selected edges of the parent view.
-     * The callback's {@link Callback#onEdgeTouched(int, int)} and
-     * {@link Callback#onEdgeDragStarted(int, int)} methods will only be invoked
-     * for edges for which edge tracking has been enabled.
-     *
-     * @param edgeFlags Combination of edge flags describing the edges to watch
-     * @see #EDGE_LEFT
-     * @see #EDGE_TOP
-     * @see #EDGE_RIGHT
-     * @see #EDGE_BOTTOM
-     */
-    public void setEdgeTrackingEnabled(int edgeFlags) {
-        mTrackingEdges = edgeFlags;
-    }
-
-    /**
-     * Return the size of an edge. This is the range in pixels along the edges of this view
-     * that will actively detect edge touches or drags if edge tracking is enabled.
-     *
-     * @return The size of an edge in pixels
-     * @see #setEdgeTrackingEnabled(int)
-     */
-    public int getEdgeSize() {
-        return mEdgeSize;
-    }
-
-    /**
-     * Capture a specific child view for dragging within the parent. The callback will be notified
-     * but {@link Callback#tryCaptureView(android.view.View, int)} will not be asked permission to
-     * capture this view.
-     *
-     * @param childView Child view to capture
-     * @param activePointerId ID of the pointer that is dragging the captured child view
-     */
-    public void captureChildView(@NonNull View childView, int activePointerId) {
-        if (childView.getParent() != mParentView) {
-            throw new IllegalArgumentException("captureChildView: parameter must be a descendant "
-                    + "of the ViewDragHelper's tracked parent view (" + mParentView + ")");
-        }
-
-        mCapturedView = childView;
-        mActivePointerId = activePointerId;
-        mCallback.onViewCaptured(childView, activePointerId);
-        setDragState(STATE_DRAGGING);
-    }
-
-    /**
-     * @return The currently captured view, or null if no view has been captured.
-     */
-    @Nullable
-    public View getCapturedView() {
-        return mCapturedView;
-    }
-
-    /**
-     * @return The ID of the pointer currently dragging the captured view,
-     *         or {@link #INVALID_POINTER}.
-     */
-    public int getActivePointerId() {
-        return mActivePointerId;
-    }
-
-    /**
-     * @return The minimum distance in pixels that the user must travel to initiate a drag
-     */
-    public int getTouchSlop() {
-        return mTouchSlop;
-    }
-
-    /**
-     * The result of a call to this method is equivalent to
-     * {@link #processTouchEvent(android.view.MotionEvent)} receiving an ACTION_CANCEL event.
-     */
-    public void cancel() {
-        mActivePointerId = INVALID_POINTER;
-        clearMotionHistory();
-
-        if (mVelocityTracker != null) {
-            mVelocityTracker.recycle();
-            mVelocityTracker = null;
-        }
-    }
-
-    /**
-     * {@link #cancel()}, but also abort all motion in progress and snap to the end of any
-     * animation.
-     */
-    public void abort() {
-        cancel();
-        if (mDragState == STATE_SETTLING) {
-            final int oldX = mScroller.getCurrX();
-            final int oldY = mScroller.getCurrY();
-            mScroller.abortAnimation();
-            final int newX = mScroller.getCurrX();
-            final int newY = mScroller.getCurrY();
-            mCallback.onViewPositionChanged(mCapturedView, newX, newY, newX - oldX, newY - oldY);
-        }
-        setDragState(STATE_IDLE);
-    }
-
-    /**
-     * Animate the view <code>child</code> to the given (left, top) position.
-     * If this method returns true, the caller should invoke {@link #continueSettling(boolean)}
-     * on each subsequent frame to continue the motion until it returns false. If this method
-     * returns false there is no further work to do to complete the movement.
-     *
-     * <p>This operation does not count as a capture event, though {@link #getCapturedView()}
-     * will still report the sliding view while the slide is in progress.</p>
-     *
-     * @param child Child view to capture and animate
-     * @param finalLeft Final left position of child
-     * @param finalTop Final top position of child
-     * @return true if animation should continue through {@link #continueSettling(boolean)} calls
-     */
-    public boolean smoothSlideViewTo(@NonNull View child, int finalLeft, int finalTop) {
-        mCapturedView = child;
-        mActivePointerId = INVALID_POINTER;
-
-        boolean continueSliding = forceSettleCapturedViewAt(finalLeft, finalTop, 0, 0);
-        if (!continueSliding && mDragState == STATE_IDLE && mCapturedView != null) {
-            // If we're in an IDLE state to begin with and aren't moving anywhere, we
-            // end up having a non-null capturedView with an IDLE dragState
-            mCapturedView = null;
-        }
-
-        return continueSliding;
-    }
-
-    /**
-     * Settle the captured view at the given (left, top) position.
-     * The appropriate velocity from prior motion will be taken into account.
-     * If this method returns true, the caller should invoke {@link #continueSettling(boolean)}
-     * on each subsequent frame to continue the motion until it returns false. If this method
-     * returns false there is no further work to do to complete the movement.
-     *
-     * @param finalLeft Settled left edge position for the captured view
-     * @param finalTop Settled top edge position for the captured view
-     * @return true if animation should continue through {@link #continueSettling(boolean)} calls
-     */
-    public boolean settleCapturedViewAt(int finalLeft, int finalTop) {
-        if (!mReleaseInProgress) {
-            throw new IllegalStateException("Cannot settleCapturedViewAt outside of a call to "
-                    + "Callback#onViewReleased");
-        }
-
-        return forceSettleCapturedViewAt(finalLeft, finalTop,
-                (int) mVelocityTracker.getXVelocity(mActivePointerId),
-                (int) mVelocityTracker.getYVelocity(mActivePointerId));
-    }
-
-    /**
-     * Settle the captured view at the given (left, top) position.
-     *
-     * @param finalLeft Target left position for the captured view
-     * @param finalTop Target top position for the captured view
-     * @param xvel Horizontal velocity
-     * @param yvel Vertical velocity
-     * @return true if animation should continue through {@link #continueSettling(boolean)} calls
-     */
-    private boolean forceSettleCapturedViewAt(int finalLeft, int finalTop, int xvel, int yvel) {
-        final int startLeft = mCapturedView.getLeft();
-        final int startTop = mCapturedView.getTop();
-        final int dx = finalLeft - startLeft;
-        final int dy = finalTop - startTop;
-
-        if (dx == 0 && dy == 0) {
-            // Nothing to do. Send callbacks, be done.
-            mScroller.abortAnimation();
-            setDragState(STATE_IDLE);
-            return false;
-        }
-
-        final int duration = computeSettleDuration(mCapturedView, dx, dy, xvel, yvel);
-        mScroller.startScroll(startLeft, startTop, dx, dy, duration);
-
-        setDragState(STATE_SETTLING);
-        return true;
-    }
-
-    private int computeSettleDuration(View child, int dx, int dy, int xvel, int yvel) {
-        xvel = clampMag(xvel, (int) mMinVelocity, (int) mMaxVelocity);
-        yvel = clampMag(yvel, (int) mMinVelocity, (int) mMaxVelocity);
-        final int absDx = Math.abs(dx);
-        final int absDy = Math.abs(dy);
-        final int absXVel = Math.abs(xvel);
-        final int absYVel = Math.abs(yvel);
-        final int addedVel = absXVel + absYVel;
-        final int addedDistance = absDx + absDy;
-
-        final float xweight = xvel != 0 ? (float) absXVel / addedVel :
-                (float) absDx / addedDistance;
-        final float yweight = yvel != 0 ? (float) absYVel / addedVel :
-                (float) absDy / addedDistance;
-
-        int xduration = computeAxisDuration(dx, xvel, mCallback.getViewHorizontalDragRange(child));
-        int yduration = computeAxisDuration(dy, yvel, mCallback.getViewVerticalDragRange(child));
-
-        return (int) (xduration * xweight + yduration * yweight);
-    }
-
-    private int computeAxisDuration(int delta, int velocity, int motionRange) {
-        if (delta == 0) {
-            return 0;
-        }
-
-        final int width = mParentView.getWidth();
-        final int halfWidth = width / 2;
-        final float distanceRatio = Math.min(1f, (float) Math.abs(delta) / width);
-        final float distance = halfWidth + halfWidth
-                * distanceInfluenceForSnapDuration(distanceRatio);
-
-        int duration;
-        velocity = Math.abs(velocity);
-        if (velocity > 0) {
-            duration = 4 * Math.round(1000 * Math.abs(distance / velocity));
-        } else {
-            final float range = (float) Math.abs(delta) / motionRange;
-            duration = (int) ((range + 1) * BASE_SETTLE_DURATION);
-        }
-        return Math.min(duration, MAX_SETTLE_DURATION);
-    }
-
-    /**
-     * Clamp the magnitude of value for absMin and absMax.
-     * If the value is below the minimum, it will be clamped to zero.
-     * If the value is above the maximum, it will be clamped to the maximum.
-     *
-     * @param value Value to clamp
-     * @param absMin Absolute value of the minimum significant value to return
-     * @param absMax Absolute value of the maximum value to return
-     * @return The clamped value with the same sign as <code>value</code>
-     */
-    private int clampMag(int value, int absMin, int absMax) {
-        final int absValue = Math.abs(value);
-        if (absValue < absMin) return 0;
-        if (absValue > absMax) return value > 0 ? absMax : -absMax;
-        return value;
-    }
-
-    /**
-     * Clamp the magnitude of value for absMin and absMax.
-     * If the value is below the minimum, it will be clamped to zero.
-     * If the value is above the maximum, it will be clamped to the maximum.
-     *
-     * @param value Value to clamp
-     * @param absMin Absolute value of the minimum significant value to return
-     * @param absMax Absolute value of the maximum value to return
-     * @return The clamped value with the same sign as <code>value</code>
-     */
-    private float clampMag(float value, float absMin, float absMax) {
-        final float absValue = Math.abs(value);
-        if (absValue < absMin) return 0;
-        if (absValue > absMax) return value > 0 ? absMax : -absMax;
-        return value;
-    }
-
-    private float distanceInfluenceForSnapDuration(float f) {
-        f -= 0.5f; // center the values about 0.
-        f *= 0.3f * (float) Math.PI / 2.0f;
-        return (float) Math.sin(f);
-    }
-
-    /**
-     * Settle the captured view based on standard free-moving fling behavior.
-     * The caller should invoke {@link #continueSettling(boolean)} on each subsequent frame
-     * to continue the motion until it returns false.
-     *
-     * @param minLeft Minimum X position for the view's left edge
-     * @param minTop Minimum Y position for the view's top edge
-     * @param maxLeft Maximum X position for the view's left edge
-     * @param maxTop Maximum Y position for the view's top edge
-     */
-    public void flingCapturedView(int minLeft, int minTop, int maxLeft, int maxTop) {
-        if (!mReleaseInProgress) {
-            throw new IllegalStateException("Cannot flingCapturedView outside of a call to "
-                    + "Callback#onViewReleased");
-        }
-
-        mScroller.fling(mCapturedView.getLeft(), mCapturedView.getTop(),
-                (int) mVelocityTracker.getXVelocity(mActivePointerId),
-                (int) mVelocityTracker.getYVelocity(mActivePointerId),
-                minLeft, maxLeft, minTop, maxTop);
-
-        setDragState(STATE_SETTLING);
-    }
-
-    /**
-     * Move the captured settling view by the appropriate amount for the current time.
-     * If <code>continueSettling</code> returns true, the caller should call it again
-     * on the next frame to continue.
-     *
-     * @param deferCallbacks true if state callbacks should be deferred via posted message.
-     *                       Set this to true if you are calling this method from
-     *                       {@link android.view.View#computeScroll()} or similar methods
-     *                       invoked as part of layout or drawing.
-     * @return true if settle is still in progress
-     */
-    public boolean continueSettling(boolean deferCallbacks) {
-        if (mDragState == STATE_SETTLING) {
-            boolean keepGoing = mScroller.computeScrollOffset();
-            final int x = mScroller.getCurrX();
-            final int y = mScroller.getCurrY();
-            final int dx = x - mCapturedView.getLeft();
-            final int dy = y - mCapturedView.getTop();
-
-            if (dx != 0) {
-                ViewCompat.offsetLeftAndRight(mCapturedView, dx);
-            }
-            if (dy != 0) {
-                ViewCompat.offsetTopAndBottom(mCapturedView, dy);
-            }
-
-            if (dx != 0 || dy != 0) {
-                mCallback.onViewPositionChanged(mCapturedView, x, y, dx, dy);
-            }
-
-            if (keepGoing && x == mScroller.getFinalX() && y == mScroller.getFinalY()) {
-                // Close enough. The interpolator/scroller might think we're still moving
-                // but the user sure doesn't.
-                mScroller.abortAnimation();
-                keepGoing = false;
-            }
-
-            if (!keepGoing) {
-                if (deferCallbacks) {
-                    mParentView.post(mSetIdleRunnable);
-                } else {
-                    setDragState(STATE_IDLE);
-                }
-            }
-        }
-
-        return mDragState == STATE_SETTLING;
-    }
-
-    /**
-     * Like all callback events this must happen on the UI thread, but release
-     * involves some extra semantics. During a release (mReleaseInProgress)
-     * is the only time it is valid to call {@link #settleCapturedViewAt(int, int)}
-     * or {@link #flingCapturedView(int, int, int, int)}.
-     */
-    private void dispatchViewReleased(float xvel, float yvel) {
-        mReleaseInProgress = true;
-        mCallback.onViewReleased(mCapturedView, xvel, yvel);
-        mReleaseInProgress = false;
-
-        if (mDragState == STATE_DRAGGING) {
-            // onViewReleased didn't call a method that would have changed this. Go idle.
-            setDragState(STATE_IDLE);
-        }
-    }
-
-    private void clearMotionHistory() {
-        if (mInitialMotionX == null) {
-            return;
-        }
-        Arrays.fill(mInitialMotionX, 0);
-        Arrays.fill(mInitialMotionY, 0);
-        Arrays.fill(mLastMotionX, 0);
-        Arrays.fill(mLastMotionY, 0);
-        Arrays.fill(mInitialEdgesTouched, 0);
-        Arrays.fill(mEdgeDragsInProgress, 0);
-        Arrays.fill(mEdgeDragsLocked, 0);
-        mPointersDown = 0;
-    }
-
-    private void clearMotionHistory(int pointerId) {
-        if (mInitialMotionX == null || !isPointerDown(pointerId)) {
-            return;
-        }
-        mInitialMotionX[pointerId] = 0;
-        mInitialMotionY[pointerId] = 0;
-        mLastMotionX[pointerId] = 0;
-        mLastMotionY[pointerId] = 0;
-        mInitialEdgesTouched[pointerId] = 0;
-        mEdgeDragsInProgress[pointerId] = 0;
-        mEdgeDragsLocked[pointerId] = 0;
-        mPointersDown &= ~(1 << pointerId);
-    }
-
-    private void ensureMotionHistorySizeForId(int pointerId) {
-        if (mInitialMotionX == null || mInitialMotionX.length <= pointerId) {
-            float[] imx = new float[pointerId + 1];
-            float[] imy = new float[pointerId + 1];
-            float[] lmx = new float[pointerId + 1];
-            float[] lmy = new float[pointerId + 1];
-            int[] iit = new int[pointerId + 1];
-            int[] edip = new int[pointerId + 1];
-            int[] edl = new int[pointerId + 1];
-
-            if (mInitialMotionX != null) {
-                System.arraycopy(mInitialMotionX, 0, imx, 0, mInitialMotionX.length);
-                System.arraycopy(mInitialMotionY, 0, imy, 0, mInitialMotionY.length);
-                System.arraycopy(mLastMotionX, 0, lmx, 0, mLastMotionX.length);
-                System.arraycopy(mLastMotionY, 0, lmy, 0, mLastMotionY.length);
-                System.arraycopy(mInitialEdgesTouched, 0, iit, 0, mInitialEdgesTouched.length);
-                System.arraycopy(mEdgeDragsInProgress, 0, edip, 0, mEdgeDragsInProgress.length);
-                System.arraycopy(mEdgeDragsLocked, 0, edl, 0, mEdgeDragsLocked.length);
-            }
-
-            mInitialMotionX = imx;
-            mInitialMotionY = imy;
-            mLastMotionX = lmx;
-            mLastMotionY = lmy;
-            mInitialEdgesTouched = iit;
-            mEdgeDragsInProgress = edip;
-            mEdgeDragsLocked = edl;
-        }
-    }
-
-    private void saveInitialMotion(float x, float y, int pointerId) {
-        ensureMotionHistorySizeForId(pointerId);
-        mInitialMotionX[pointerId] = mLastMotionX[pointerId] = x;
-        mInitialMotionY[pointerId] = mLastMotionY[pointerId] = y;
-        mInitialEdgesTouched[pointerId] = getEdgesTouched((int) x, (int) y);
-        mPointersDown |= 1 << pointerId;
-    }
-
-    private void saveLastMotion(MotionEvent ev) {
-        final int pointerCount = ev.getPointerCount();
-        for (int i = 0; i < pointerCount; i++) {
-            final int pointerId = ev.getPointerId(i);
-            // If pointer is invalid then skip saving on ACTION_MOVE.
-            if (!isValidPointerForActionMove(pointerId)) {
-                continue;
-            }
-            final float x = ev.getX(i);
-            final float y = ev.getY(i);
-            mLastMotionX[pointerId] = x;
-            mLastMotionY[pointerId] = y;
-        }
-    }
-
-    /**
-     * Check if the given pointer ID represents a pointer that is currently down (to the best
-     * of the ViewDragHelper's knowledge).
-     *
-     * <p>The state used to report this information is populated by the methods
-     * {@link #shouldInterceptTouchEvent(android.view.MotionEvent)} or
-     * {@link #processTouchEvent(android.view.MotionEvent)}. If one of these methods has not
-     * been called for all relevant MotionEvents to track, the information reported
-     * by this method may be stale or incorrect.</p>
-     *
-     * @param pointerId pointer ID to check; corresponds to IDs provided by MotionEvent
-     * @return true if the pointer with the given ID is still down
-     */
-    public boolean isPointerDown(int pointerId) {
-        return (mPointersDown & 1 << pointerId) != 0;
-    }
-
-    void setDragState(int state) {
-        mParentView.removeCallbacks(mSetIdleRunnable);
-        if (mDragState != state) {
-            mDragState = state;
-            mCallback.onViewDragStateChanged(state);
-            if (mDragState == STATE_IDLE) {
-                mCapturedView = null;
-            }
-        }
-    }
-
-    /**
-     * Attempt to capture the view with the given pointer ID. The callback will be involved.
-     * This will put us into the "dragging" state. If we've already captured this view with
-     * this pointer this method will immediately return true without consulting the callback.
-     *
-     * @param toCapture View to capture
-     * @param pointerId Pointer to capture with
-     * @return true if capture was successful
-     */
-    boolean tryCaptureViewForDrag(View toCapture, int pointerId) {
-        if (toCapture == mCapturedView && mActivePointerId == pointerId) {
-            // Already done!
-            return true;
-        }
-        if (toCapture != null && mCallback.tryCaptureView(toCapture, pointerId)) {
-            mActivePointerId = pointerId;
-            captureChildView(toCapture, pointerId);
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Tests scrollability within child views of v given a delta of dx.
-     *
-     * @param v View to test for horizontal scrollability
-     * @param checkV Whether the view v passed should itself be checked for scrollability (true),
-     *               or just its children (false).
-     * @param dx Delta scrolled in pixels along the X axis
-     * @param dy Delta scrolled in pixels along the Y axis
-     * @param x X coordinate of the active touch point
-     * @param y Y coordinate of the active touch point
-     * @return true if child views of v can be scrolled by delta of dx.
-     */
-    protected boolean canScroll(@NonNull View v, boolean checkV, int dx, int dy, int x, int y) {
-        if (v instanceof ViewGroup) {
-            final ViewGroup group = (ViewGroup) v;
-            final int scrollX = v.getScrollX();
-            final int scrollY = v.getScrollY();
-            final int count = group.getChildCount();
-            // Count backwards - let topmost views consume scroll distance first.
-            for (int i = count - 1; i >= 0; i--) {
-                // TODO: Add versioned support here for transformed views.
-                // This will not work for transformed views in Honeycomb+
-                final View child = group.getChildAt(i);
-                if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight()
-                        && y + scrollY >= child.getTop() && y + scrollY < child.getBottom()
-                        && canScroll(child, true, dx, dy, x + scrollX - child.getLeft(),
-                                y + scrollY - child.getTop())) {
-                    return true;
-                }
-            }
-        }
-
-        return checkV && (v.canScrollHorizontally(-dx) || v.canScrollVertically(-dy));
-    }
-
-    /**
-     * Check if this event as provided to the parent view's onInterceptTouchEvent should
-     * cause the parent to intercept the touch event stream.
-     *
-     * @param ev MotionEvent provided to onInterceptTouchEvent
-     * @return true if the parent view should return true from onInterceptTouchEvent
-     */
-    public boolean shouldInterceptTouchEvent(@NonNull MotionEvent ev) {
-        final int action = ev.getActionMasked();
-        final int actionIndex = ev.getActionIndex();
-
-        if (action == MotionEvent.ACTION_DOWN) {
-            // Reset things for a new event stream, just in case we didn't get
-            // the whole previous stream.
-            cancel();
-        }
-
-        if (mVelocityTracker == null) {
-            mVelocityTracker = VelocityTracker.obtain();
-        }
-        mVelocityTracker.addMovement(ev);
-
-        switch (action) {
-            case MotionEvent.ACTION_DOWN: {
-                final float x = ev.getX();
-                final float y = ev.getY();
-                final int pointerId = ev.getPointerId(0);
-                saveInitialMotion(x, y, pointerId);
-
-                final View toCapture = findTopChildUnder((int) x, (int) y);
-
-                // Catch a settling view if possible.
-                if (toCapture == mCapturedView && mDragState == STATE_SETTLING) {
-                    tryCaptureViewForDrag(toCapture, pointerId);
-                }
-
-                final int edgesTouched = mInitialEdgesTouched[pointerId];
-                if ((edgesTouched & mTrackingEdges) != 0) {
-                    mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId);
-                }
-                break;
-            }
-
-            case MotionEvent.ACTION_POINTER_DOWN: {
-                final int pointerId = ev.getPointerId(actionIndex);
-                final float x = ev.getX(actionIndex);
-                final float y = ev.getY(actionIndex);
-
-                saveInitialMotion(x, y, pointerId);
-
-                // A ViewDragHelper can only manipulate one view at a time.
-                if (mDragState == STATE_IDLE) {
-                    final int edgesTouched = mInitialEdgesTouched[pointerId];
-                    if ((edgesTouched & mTrackingEdges) != 0) {
-                        mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId);
-                    }
-                } else if (mDragState == STATE_SETTLING) {
-                    // Catch a settling view if possible.
-                    final View toCapture = findTopChildUnder((int) x, (int) y);
-                    if (toCapture == mCapturedView) {
-                        tryCaptureViewForDrag(toCapture, pointerId);
-                    }
-                }
-                break;
-            }
-
-            case MotionEvent.ACTION_MOVE: {
-                if (mInitialMotionX == null || mInitialMotionY == null) break;
-
-                // First to cross a touch slop over a draggable view wins. Also report edge drags.
-                final int pointerCount = ev.getPointerCount();
-                for (int i = 0; i < pointerCount; i++) {
-                    final int pointerId = ev.getPointerId(i);
-
-                    // If pointer is invalid then skip the ACTION_MOVE.
-                    if (!isValidPointerForActionMove(pointerId)) continue;
-
-                    final float x = ev.getX(i);
-                    final float y = ev.getY(i);
-                    final float dx = x - mInitialMotionX[pointerId];
-                    final float dy = y - mInitialMotionY[pointerId];
-
-                    final View toCapture = findTopChildUnder((int) x, (int) y);
-                    final boolean pastSlop = toCapture != null && checkTouchSlop(toCapture, dx, dy);
-                    if (pastSlop) {
-                        // check the callback's
-                        // getView[Horizontal|Vertical]DragRange methods to know
-                        // if you can move at all along an axis, then see if it
-                        // would clamp to the same value. If you can't move at
-                        // all in every dimension with a nonzero range, bail.
-                        final int oldLeft = toCapture.getLeft();
-                        final int targetLeft = oldLeft + (int) dx;
-                        final int newLeft = mCallback.clampViewPositionHorizontal(toCapture,
-                                targetLeft, (int) dx);
-                        final int oldTop = toCapture.getTop();
-                        final int targetTop = oldTop + (int) dy;
-                        final int newTop = mCallback.clampViewPositionVertical(toCapture, targetTop,
-                                (int) dy);
-                        final int hDragRange = mCallback.getViewHorizontalDragRange(toCapture);
-                        final int vDragRange = mCallback.getViewVerticalDragRange(toCapture);
-                        if ((hDragRange == 0 || (hDragRange > 0 && newLeft == oldLeft))
-                                && (vDragRange == 0 || (vDragRange > 0 && newTop == oldTop))) {
-                            break;
-                        }
-                    }
-                    reportNewEdgeDrags(dx, dy, pointerId);
-                    if (mDragState == STATE_DRAGGING) {
-                        // Callback might have started an edge drag
-                        break;
-                    }
-
-                    if (pastSlop && tryCaptureViewForDrag(toCapture, pointerId)) {
-                        break;
-                    }
-                }
-                saveLastMotion(ev);
-                break;
-            }
-
-            case MotionEvent.ACTION_POINTER_UP: {
-                final int pointerId = ev.getPointerId(actionIndex);
-                clearMotionHistory(pointerId);
-                break;
-            }
-
-            case MotionEvent.ACTION_UP:
-            case MotionEvent.ACTION_CANCEL: {
-                cancel();
-                break;
-            }
-        }
-
-        return mDragState == STATE_DRAGGING;
-    }
-
-    /**
-     * Process a touch event received by the parent view. This method will dispatch callback events
-     * as needed before returning. The parent view's onTouchEvent implementation should call this.
-     *
-     * @param ev The touch event received by the parent view
-     */
-    public void processTouchEvent(@NonNull MotionEvent ev) {
-        final int action = ev.getActionMasked();
-        final int actionIndex = ev.getActionIndex();
-
-        if (action == MotionEvent.ACTION_DOWN) {
-            // Reset things for a new event stream, just in case we didn't get
-            // the whole previous stream.
-            cancel();
-        }
-
-        if (mVelocityTracker == null) {
-            mVelocityTracker = VelocityTracker.obtain();
-        }
-        mVelocityTracker.addMovement(ev);
-
-        switch (action) {
-            case MotionEvent.ACTION_DOWN: {
-                final float x = ev.getX();
-                final float y = ev.getY();
-                final int pointerId = ev.getPointerId(0);
-                final View toCapture = findTopChildUnder((int) x, (int) y);
-
-                saveInitialMotion(x, y, pointerId);
-
-                // Since the parent is already directly processing this touch event,
-                // there is no reason to delay for a slop before dragging.
-                // Start immediately if possible.
-                tryCaptureViewForDrag(toCapture, pointerId);
-
-                final int edgesTouched = mInitialEdgesTouched[pointerId];
-                if ((edgesTouched & mTrackingEdges) != 0) {
-                    mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId);
-                }
-                break;
-            }
-
-            case MotionEvent.ACTION_POINTER_DOWN: {
-                final int pointerId = ev.getPointerId(actionIndex);
-                final float x = ev.getX(actionIndex);
-                final float y = ev.getY(actionIndex);
-
-                saveInitialMotion(x, y, pointerId);
-
-                // A ViewDragHelper can only manipulate one view at a time.
-                if (mDragState == STATE_IDLE) {
-                    // If we're idle we can do anything! Treat it like a normal down event.
-
-                    final View toCapture = findTopChildUnder((int) x, (int) y);
-                    tryCaptureViewForDrag(toCapture, pointerId);
-
-                    final int edgesTouched = mInitialEdgesTouched[pointerId];
-                    if ((edgesTouched & mTrackingEdges) != 0) {
-                        mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId);
-                    }
-                } else if (isCapturedViewUnder((int) x, (int) y)) {
-                    // We're still tracking a captured view. If the same view is under this
-                    // point, we'll swap to controlling it with this pointer instead.
-                    // (This will still work if we're "catching" a settling view.)
-
-                    tryCaptureViewForDrag(mCapturedView, pointerId);
-                }
-                break;
-            }
-
-            case MotionEvent.ACTION_MOVE: {
-                if (mDragState == STATE_DRAGGING) {
-                    // If pointer is invalid then skip the ACTION_MOVE.
-                    if (!isValidPointerForActionMove(mActivePointerId)) break;
-
-                    final int index = ev.findPointerIndex(mActivePointerId);
-                    final float x = ev.getX(index);
-                    final float y = ev.getY(index);
-                    final int idx = (int) (x - mLastMotionX[mActivePointerId]);
-                    final int idy = (int) (y - mLastMotionY[mActivePointerId]);
-
-                    dragTo(mCapturedView.getLeft() + idx, mCapturedView.getTop() + idy, idx, idy);
-
-                    saveLastMotion(ev);
-                } else {
-                    // Check to see if any pointer is now over a draggable view.
-                    final int pointerCount = ev.getPointerCount();
-                    for (int i = 0; i < pointerCount; i++) {
-                        final int pointerId = ev.getPointerId(i);
-
-                        // If pointer is invalid then skip the ACTION_MOVE.
-                        if (!isValidPointerForActionMove(pointerId)) continue;
-
-                        final float x = ev.getX(i);
-                        final float y = ev.getY(i);
-                        final float dx = x - mInitialMotionX[pointerId];
-                        final float dy = y - mInitialMotionY[pointerId];
-
-                        reportNewEdgeDrags(dx, dy, pointerId);
-                        if (mDragState == STATE_DRAGGING) {
-                            // Callback might have started an edge drag.
-                            break;
-                        }
-
-                        final View toCapture = findTopChildUnder((int) x, (int) y);
-                        if (checkTouchSlop(toCapture, dx, dy)
-                                && tryCaptureViewForDrag(toCapture, pointerId)) {
-                            break;
-                        }
-                    }
-                    saveLastMotion(ev);
-                }
-                break;
-            }
-
-            case MotionEvent.ACTION_POINTER_UP: {
-                final int pointerId = ev.getPointerId(actionIndex);
-                if (mDragState == STATE_DRAGGING && pointerId == mActivePointerId) {
-                    // Try to find another pointer that's still holding on to the captured view.
-                    int newActivePointer = INVALID_POINTER;
-                    final int pointerCount = ev.getPointerCount();
-                    for (int i = 0; i < pointerCount; i++) {
-                        final int id = ev.getPointerId(i);
-                        if (id == mActivePointerId) {
-                            // This one's going away, skip.
-                            continue;
-                        }
-
-                        final float x = ev.getX(i);
-                        final float y = ev.getY(i);
-                        if (findTopChildUnder((int) x, (int) y) == mCapturedView
-                                && tryCaptureViewForDrag(mCapturedView, id)) {
-                            newActivePointer = mActivePointerId;
-                            break;
-                        }
-                    }
-
-                    if (newActivePointer == INVALID_POINTER) {
-                        // We didn't find another pointer still touching the view, release it.
-                        releaseViewForPointerUp();
-                    }
-                }
-                clearMotionHistory(pointerId);
-                break;
-            }
-
-            case MotionEvent.ACTION_UP: {
-                if (mDragState == STATE_DRAGGING) {
-                    releaseViewForPointerUp();
-                }
-                cancel();
-                break;
-            }
-
-            case MotionEvent.ACTION_CANCEL: {
-                if (mDragState == STATE_DRAGGING) {
-                    dispatchViewReleased(0, 0);
-                }
-                cancel();
-                break;
-            }
-        }
-    }
-
-    private void reportNewEdgeDrags(float dx, float dy, int pointerId) {
-        int dragsStarted = 0;
-        if (checkNewEdgeDrag(dx, dy, pointerId, EDGE_LEFT)) {
-            dragsStarted |= EDGE_LEFT;
-        }
-        if (checkNewEdgeDrag(dy, dx, pointerId, EDGE_TOP)) {
-            dragsStarted |= EDGE_TOP;
-        }
-        if (checkNewEdgeDrag(dx, dy, pointerId, EDGE_RIGHT)) {
-            dragsStarted |= EDGE_RIGHT;
-        }
-        if (checkNewEdgeDrag(dy, dx, pointerId, EDGE_BOTTOM)) {
-            dragsStarted |= EDGE_BOTTOM;
-        }
-
-        if (dragsStarted != 0) {
-            mEdgeDragsInProgress[pointerId] |= dragsStarted;
-            mCallback.onEdgeDragStarted(dragsStarted, pointerId);
-        }
-    }
-
-    private boolean checkNewEdgeDrag(float delta, float odelta, int pointerId, int edge) {
-        final float absDelta = Math.abs(delta);
-        final float absODelta = Math.abs(odelta);
-
-        if ((mInitialEdgesTouched[pointerId] & edge) != edge  || (mTrackingEdges & edge) == 0
-                || (mEdgeDragsLocked[pointerId] & edge) == edge
-                || (mEdgeDragsInProgress[pointerId] & edge) == edge
-                || (absDelta <= mTouchSlop && absODelta <= mTouchSlop)) {
-            return false;
-        }
-        if (absDelta < absODelta * 0.5f && mCallback.onEdgeLock(edge)) {
-            mEdgeDragsLocked[pointerId] |= edge;
-            return false;
-        }
-        return (mEdgeDragsInProgress[pointerId] & edge) == 0 && absDelta > mTouchSlop;
-    }
-
-    /**
-     * Check if we've crossed a reasonable touch slop for the given child view.
-     * If the child cannot be dragged along the horizontal or vertical axis, motion
-     * along that axis will not count toward the slop check.
-     *
-     * @param child Child to check
-     * @param dx Motion since initial position along X axis
-     * @param dy Motion since initial position along Y axis
-     * @return true if the touch slop has been crossed
-     */
-    private boolean checkTouchSlop(View child, float dx, float dy) {
-        if (child == null) {
-            return false;
-        }
-        final boolean checkHorizontal = mCallback.getViewHorizontalDragRange(child) > 0;
-        final boolean checkVertical = mCallback.getViewVerticalDragRange(child) > 0;
-
-        if (checkHorizontal && checkVertical) {
-            return dx * dx + dy * dy > mTouchSlop * mTouchSlop;
-        } else if (checkHorizontal) {
-            return Math.abs(dx) > mTouchSlop;
-        } else if (checkVertical) {
-            return Math.abs(dy) > mTouchSlop;
-        }
-        return false;
-    }
-
-    /**
-     * Check if any pointer tracked in the current gesture has crossed
-     * the required slop threshold.
-     *
-     * <p>This depends on internal state populated by
-     * {@link #shouldInterceptTouchEvent(android.view.MotionEvent)} or
-     * {@link #processTouchEvent(android.view.MotionEvent)}. You should only rely on
-     * the results of this method after all currently available touch data
-     * has been provided to one of these two methods.</p>
-     *
-     * @param directions Combination of direction flags, see {@link #DIRECTION_HORIZONTAL},
-     *                   {@link #DIRECTION_VERTICAL}, {@link #DIRECTION_ALL}
-     * @return true if the slop threshold has been crossed, false otherwise
-     */
-    public boolean checkTouchSlop(int directions) {
-        final int count = mInitialMotionX.length;
-        for (int i = 0; i < count; i++) {
-            if (checkTouchSlop(directions, i)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Check if the specified pointer tracked in the current gesture has crossed
-     * the required slop threshold.
-     *
-     * <p>This depends on internal state populated by
-     * {@link #shouldInterceptTouchEvent(android.view.MotionEvent)} or
-     * {@link #processTouchEvent(android.view.MotionEvent)}. You should only rely on
-     * the results of this method after all currently available touch data
-     * has been provided to one of these two methods.</p>
-     *
-     * @param directions Combination of direction flags, see {@link #DIRECTION_HORIZONTAL},
-     *                   {@link #DIRECTION_VERTICAL}, {@link #DIRECTION_ALL}
-     * @param pointerId ID of the pointer to slop check as specified by MotionEvent
-     * @return true if the slop threshold has been crossed, false otherwise
-     */
-    public boolean checkTouchSlop(int directions, int pointerId) {
-        if (!isPointerDown(pointerId)) {
-            return false;
-        }
-
-        final boolean checkHorizontal = (directions & DIRECTION_HORIZONTAL) == DIRECTION_HORIZONTAL;
-        final boolean checkVertical = (directions & DIRECTION_VERTICAL) == DIRECTION_VERTICAL;
-
-        final float dx = mLastMotionX[pointerId] - mInitialMotionX[pointerId];
-        final float dy = mLastMotionY[pointerId] - mInitialMotionY[pointerId];
-
-        if (checkHorizontal && checkVertical) {
-            return dx * dx + dy * dy > mTouchSlop * mTouchSlop;
-        } else if (checkHorizontal) {
-            return Math.abs(dx) > mTouchSlop;
-        } else if (checkVertical) {
-            return Math.abs(dy) > mTouchSlop;
-        }
-        return false;
-    }
-
-    /**
-     * Check if any of the edges specified were initially touched in the currently active gesture.
-     * If there is no currently active gesture this method will return false.
-     *
-     * @param edges Edges to check for an initial edge touch. See {@link #EDGE_LEFT},
-     *              {@link #EDGE_TOP}, {@link #EDGE_RIGHT}, {@link #EDGE_BOTTOM} and
-     *              {@link #EDGE_ALL}
-     * @return true if any of the edges specified were initially touched in the current gesture
-     */
-    public boolean isEdgeTouched(int edges) {
-        final int count = mInitialEdgesTouched.length;
-        for (int i = 0; i < count; i++) {
-            if (isEdgeTouched(edges, i)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Check if any of the edges specified were initially touched by the pointer with
-     * the specified ID. If there is no currently active gesture or if there is no pointer with
-     * the given ID currently down this method will return false.
-     *
-     * @param edges Edges to check for an initial edge touch. See {@link #EDGE_LEFT},
-     *              {@link #EDGE_TOP}, {@link #EDGE_RIGHT}, {@link #EDGE_BOTTOM} and
-     *              {@link #EDGE_ALL}
-     * @return true if any of the edges specified were initially touched in the current gesture
-     */
-    public boolean isEdgeTouched(int edges, int pointerId) {
-        return isPointerDown(pointerId) && (mInitialEdgesTouched[pointerId] & edges) != 0;
-    }
-
-    private void releaseViewForPointerUp() {
-        mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity);
-        final float xvel = clampMag(
-                mVelocityTracker.getXVelocity(mActivePointerId),
-                mMinVelocity, mMaxVelocity);
-        final float yvel = clampMag(
-                mVelocityTracker.getYVelocity(mActivePointerId),
-                mMinVelocity, mMaxVelocity);
-        dispatchViewReleased(xvel, yvel);
-    }
-
-    private void dragTo(int left, int top, int dx, int dy) {
-        int clampedX = left;
-        int clampedY = top;
-        final int oldLeft = mCapturedView.getLeft();
-        final int oldTop = mCapturedView.getTop();
-        if (dx != 0) {
-            clampedX = mCallback.clampViewPositionHorizontal(mCapturedView, left, dx);
-            ViewCompat.offsetLeftAndRight(mCapturedView, clampedX - oldLeft);
-        }
-        if (dy != 0) {
-            clampedY = mCallback.clampViewPositionVertical(mCapturedView, top, dy);
-            ViewCompat.offsetTopAndBottom(mCapturedView, clampedY - oldTop);
-        }
-
-        if (dx != 0 || dy != 0) {
-            final int clampedDx = clampedX - oldLeft;
-            final int clampedDy = clampedY - oldTop;
-            mCallback.onViewPositionChanged(mCapturedView, clampedX, clampedY,
-                    clampedDx, clampedDy);
-        }
-    }
-
-    /**
-     * Determine if the currently captured view is under the given point in the
-     * parent view's coordinate system. If there is no captured view this method
-     * will return false.
-     *
-     * @param x X position to test in the parent's coordinate system
-     * @param y Y position to test in the parent's coordinate system
-     * @return true if the captured view is under the given point, false otherwise
-     */
-    public boolean isCapturedViewUnder(int x, int y) {
-        return isViewUnder(mCapturedView, x, y);
-    }
-
-    /**
-     * Determine if the supplied view is under the given point in the
-     * parent view's coordinate system.
-     *
-     * @param view Child view of the parent to hit test
-     * @param x X position to test in the parent's coordinate system
-     * @param y Y position to test in the parent's coordinate system
-     * @return true if the supplied view is under the given point, false otherwise
-     */
-    public boolean isViewUnder(@Nullable View view, int x, int y) {
-        if (view == null) {
-            return false;
-        }
-        return x >= view.getLeft()
-                && x < view.getRight()
-                && y >= view.getTop()
-                && y < view.getBottom();
-    }
-
-    /**
-     * Find the topmost child under the given point within the parent view's coordinate system.
-     * The child order is determined using {@link Callback#getOrderedChildIndex(int)}.
-     *
-     * @param x X position to test in the parent's coordinate system
-     * @param y Y position to test in the parent's coordinate system
-     * @return The topmost child view under (x, y) or null if none found.
-     */
-    @Nullable
-    public View findTopChildUnder(int x, int y) {
-        final int childCount = mParentView.getChildCount();
-        for (int i = childCount - 1; i >= 0; i--) {
-            final View child = mParentView.getChildAt(mCallback.getOrderedChildIndex(i));
-            if (x >= child.getLeft() && x < child.getRight()
-                    && y >= child.getTop() && y < child.getBottom()) {
-                return child;
-            }
-        }
-        return null;
-    }
-
-    private int getEdgesTouched(int x, int y) {
-        int result = 0;
-
-        if (x < mParentView.getLeft() + mEdgeSize) result |= EDGE_LEFT;
-        if (y < mParentView.getTop() + mEdgeSize) result |= EDGE_TOP;
-        if (x > mParentView.getRight() - mEdgeSize) result |= EDGE_RIGHT;
-        if (y > mParentView.getBottom() - mEdgeSize) result |= EDGE_BOTTOM;
-
-        return result;
-    }
-
-    private boolean isValidPointerForActionMove(int pointerId) {
-        if (!isPointerDown(pointerId)) {
-            Log.e(TAG, "Ignoring pointerId=" + pointerId + " because ACTION_DOWN was not received "
-                    + "for this pointer before ACTION_MOVE. It likely happened because "
-                    + " ViewDragHelper did not receive all the events in the event stream.");
-            return false;
-        }
-        return true;
-    }
-}
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/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/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/AndroidManifest.xml b/core-utils/src/main/AndroidManifest.xml
similarity index 100%
rename from core-utils/AndroidManifest.xml
rename to core-utils/src/main/AndroidManifest.xml
diff --git a/core-utils/java/android/support/v4/content/WakefulBroadcastReceiver.java b/core-utils/src/main/java/android/support/v4/content/WakefulBroadcastReceiver.java
similarity index 100%
rename from core-utils/java/android/support/v4/content/WakefulBroadcastReceiver.java
rename to core-utils/src/main/java/android/support/v4/content/WakefulBroadcastReceiver.java
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/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/AndroidManifest.xml b/customtabs/src/main/AndroidManifest.xml
similarity index 100%
rename from customtabs/AndroidManifest.xml
rename to customtabs/src/main/AndroidManifest.xml
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/src/main/java/androidx/browser/browseractions/BrowserActionsFallbackMenuDialog.java b/customtabs/src/main/java/androidx/browser/browseractions/BrowserActionsFallbackMenuDialog.java
index 3e0674c..d0a4956 100644
--- a/customtabs/src/main/java/androidx/browser/browseractions/BrowserActionsFallbackMenuDialog.java
+++ b/customtabs/src/main/java/androidx/browser/browseractions/BrowserActionsFallbackMenuDialog.java
@@ -38,7 +38,7 @@
     private final View mContentView;
 
     BrowserActionsFallbackMenuDialog(Context context, View contentView) {
-        super(context, android.support.v7.appcompat.R.style.Theme_AppCompat_Light_Dialog);
+        super(context, android.support.customtabs.R.style.Theme_AppCompat_Light_Dialog);
         mContentView = contentView;
     }
 
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/customview/src/main/java/android/support/v4/widget/ViewDragHelper.java b/customview/src/main/java/android/support/v4/widget/ViewDragHelper.java
new file mode 100644
index 0000000..d1ca823
--- /dev/null
+++ b/customview/src/main/java/android/support/v4/widget/ViewDragHelper.java
@@ -0,0 +1,1517 @@
+/*
+ * 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.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.Px;
+import android.support.v4.view.ViewCompat;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+import android.view.animation.Interpolator;
+import android.widget.OverScroller;
+
+import java.util.Arrays;
+
+/**
+ * ViewDragHelper is a utility class for writing custom ViewGroups. It offers a number
+ * of useful operations and state tracking for allowing a user to drag and reposition
+ * views within their parent ViewGroup.
+ */
+public class ViewDragHelper {
+    private static final String TAG = "ViewDragHelper";
+
+    /**
+     * A null/invalid pointer ID.
+     */
+    public static final int INVALID_POINTER = -1;
+
+    /**
+     * A view is not currently being dragged or animating as a result of a fling/snap.
+     */
+    public static final int STATE_IDLE = 0;
+
+    /**
+     * 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 = 1;
+
+    /**
+     * A view is currently settling into place as a result of a fling or
+     * predefined non-interactive motion.
+     */
+    public static final int STATE_SETTLING = 2;
+
+    /**
+     * Edge flag indicating that the left edge should be affected.
+     */
+    public static final int EDGE_LEFT = 1 << 0;
+
+    /**
+     * Edge flag indicating that the right edge should be affected.
+     */
+    public static final int EDGE_RIGHT = 1 << 1;
+
+    /**
+     * Edge flag indicating that the top edge should be affected.
+     */
+    public static final int EDGE_TOP = 1 << 2;
+
+    /**
+     * Edge flag indicating that the bottom edge should be affected.
+     */
+    public static final int EDGE_BOTTOM = 1 << 3;
+
+    /**
+     * Edge flag set indicating all edges should be affected.
+     */
+    public static final int EDGE_ALL = EDGE_LEFT | EDGE_TOP | EDGE_RIGHT | EDGE_BOTTOM;
+
+    /**
+     * Indicates that a check should occur along the horizontal axis
+     */
+    public static final int DIRECTION_HORIZONTAL = 1 << 0;
+
+    /**
+     * Indicates that a check should occur along the vertical axis
+     */
+    public static final int DIRECTION_VERTICAL = 1 << 1;
+
+    /**
+     * Indicates that a check should occur along all axes
+     */
+    public static final int DIRECTION_ALL = DIRECTION_HORIZONTAL | DIRECTION_VERTICAL;
+
+    private static final int EDGE_SIZE = 20; // dp
+
+    private static final int BASE_SETTLE_DURATION = 256; // ms
+    private static final int MAX_SETTLE_DURATION = 600; // ms
+
+    // Current drag state; idle, dragging or settling
+    private int mDragState;
+
+    // Distance to travel before a drag may begin
+    private int mTouchSlop;
+
+    // Last known position/pointer tracking
+    private int mActivePointerId = INVALID_POINTER;
+    private float[] mInitialMotionX;
+    private float[] mInitialMotionY;
+    private float[] mLastMotionX;
+    private float[] mLastMotionY;
+    private int[] mInitialEdgesTouched;
+    private int[] mEdgeDragsInProgress;
+    private int[] mEdgeDragsLocked;
+    private int mPointersDown;
+
+    private VelocityTracker mVelocityTracker;
+    private float mMaxVelocity;
+    private float mMinVelocity;
+
+    private int mEdgeSize;
+    private int mTrackingEdges;
+
+    private OverScroller mScroller;
+
+    private final Callback mCallback;
+
+    private View mCapturedView;
+    private boolean mReleaseInProgress;
+
+    private final ViewGroup mParentView;
+
+    /**
+     * A Callback is used as a communication channel with the ViewDragHelper back to the
+     * parent view using it. <code>on*</code>methods are invoked on siginficant events and several
+     * accessor methods are expected to provide the ViewDragHelper with more information
+     * about the state of the parent view upon request. The callback also makes decisions
+     * governing the range and draggability of child views.
+     */
+    public abstract static class Callback {
+        /**
+         * Called when the drag state changes. See the <code>STATE_*</code> constants
+         * for more information.
+         *
+         * @param state The new drag state
+         *
+         * @see #STATE_IDLE
+         * @see #STATE_DRAGGING
+         * @see #STATE_SETTLING
+         */
+        public void onViewDragStateChanged(int state) {}
+
+        /**
+         * Called when the captured view's position changes as the result of a drag or settle.
+         *
+         * @param changedView View whose position changed
+         * @param left New X coordinate of the left edge of the view
+         * @param top New Y coordinate of the top edge of the view
+         * @param dx Change in X position from the last call
+         * @param dy Change in Y position from the last call
+         */
+        public void onViewPositionChanged(@NonNull View changedView, int left, int top, @Px int dx,
+                @Px int dy) {
+        }
+
+        /**
+         * Called when a child view is captured for dragging or settling. The ID of the pointer
+         * currently dragging the captured view is supplied. If activePointerId is
+         * identified as {@link #INVALID_POINTER} the capture is programmatic instead of
+         * pointer-initiated.
+         *
+         * @param capturedChild Child view that was captured
+         * @param activePointerId Pointer id tracking the child capture
+         */
+        public void onViewCaptured(@NonNull View capturedChild, int activePointerId) {}
+
+        /**
+         * Called when the child view is no longer being actively dragged.
+         * The fling velocity is also supplied, if relevant. The velocity values may
+         * be clamped to system minimums or maximums.
+         *
+         * <p>Calling code may decide to fling or otherwise release the view to let it
+         * settle into place. It should do so using {@link #settleCapturedViewAt(int, int)}
+         * or {@link #flingCapturedView(int, int, int, int)}. If the Callback invokes
+         * one of these methods, the ViewDragHelper will enter {@link #STATE_SETTLING}
+         * and the view capture will not fully end until it comes to a complete stop.
+         * If neither of these methods is invoked before <code>onViewReleased</code> returns,
+         * the view will stop in place and the ViewDragHelper will return to
+         * {@link #STATE_IDLE}.</p>
+         *
+         * @param releasedChild The captured child view now being released
+         * @param xvel X velocity of the pointer as it left the screen in pixels per second.
+         * @param yvel Y velocity of the pointer as it left the screen in pixels per second.
+         */
+        public void onViewReleased(@NonNull View releasedChild, float xvel, float yvel) {}
+
+        /**
+         * Called when one of the subscribed edges in the parent view has been touched
+         * by the user while no child view is currently captured.
+         *
+         * @param edgeFlags A combination of edge flags describing the edge(s) currently touched
+         * @param pointerId ID of the pointer touching the described edge(s)
+         * @see #EDGE_LEFT
+         * @see #EDGE_TOP
+         * @see #EDGE_RIGHT
+         * @see #EDGE_BOTTOM
+         */
+        public void onEdgeTouched(int edgeFlags, int pointerId) {}
+
+        /**
+         * Called when the given edge may become locked. This can happen if an edge drag
+         * was preliminarily rejected before beginning, but after {@link #onEdgeTouched(int, int)}
+         * was called. This method should return true to lock this edge or false to leave it
+         * unlocked. The default behavior is to leave edges unlocked.
+         *
+         * @param edgeFlags A combination of edge flags describing the edge(s) locked
+         * @return true to lock the edge, false to leave it unlocked
+         */
+        public boolean onEdgeLock(int edgeFlags) {
+            return false;
+        }
+
+        /**
+         * Called when the user has started a deliberate drag away from one
+         * of the subscribed edges in the parent view while no child view is currently captured.
+         *
+         * @param edgeFlags A combination of edge flags describing the edge(s) dragged
+         * @param pointerId ID of the pointer touching the described edge(s)
+         * @see #EDGE_LEFT
+         * @see #EDGE_TOP
+         * @see #EDGE_RIGHT
+         * @see #EDGE_BOTTOM
+         */
+        public void onEdgeDragStarted(int edgeFlags, int pointerId) {}
+
+        /**
+         * Called to determine the Z-order of child views.
+         *
+         * @param index the ordered position to query for
+         * @return index of the view that should be ordered at position <code>index</code>
+         */
+        public int getOrderedChildIndex(int index) {
+            return index;
+        }
+
+        /**
+         * Return the magnitude of a draggable child view's horizontal range of motion in pixels.
+         * This method should return 0 for views that cannot move horizontally.
+         *
+         * @param child Child view to check
+         * @return range of horizontal motion in pixels
+         */
+        public int getViewHorizontalDragRange(@NonNull View child) {
+            return 0;
+        }
+
+        /**
+         * Return the magnitude of a draggable child view's vertical range of motion in pixels.
+         * This method should return 0 for views that cannot move vertically.
+         *
+         * @param child Child view to check
+         * @return range of vertical motion in pixels
+         */
+        public int getViewVerticalDragRange(@NonNull View child) {
+            return 0;
+        }
+
+        /**
+         * Called when the user's input indicates that they want to capture the given child view
+         * with the pointer indicated by pointerId. The callback should return true if the user
+         * is permitted to drag the given view with the indicated pointer.
+         *
+         * <p>ViewDragHelper may call this method multiple times for the same view even if
+         * the view is already captured; this indicates that a new pointer is trying to take
+         * control of the view.</p>
+         *
+         * <p>If this method returns true, a call to {@link #onViewCaptured(android.view.View, int)}
+         * will follow if the capture is successful.</p>
+         *
+         * @param child Child the user is attempting to capture
+         * @param pointerId ID of the pointer attempting the capture
+         * @return true if capture should be allowed, false otherwise
+         */
+        public abstract boolean tryCaptureView(@NonNull View child, int pointerId);
+
+        /**
+         * Restrict the motion of the dragged child view along the horizontal axis.
+         * The default implementation does not allow horizontal motion; the extending
+         * class must override this method and provide the desired clamping.
+         *
+         *
+         * @param child Child view being dragged
+         * @param left Attempted motion along the X axis
+         * @param dx Proposed change in position for left
+         * @return The new clamped position for left
+         */
+        public int clampViewPositionHorizontal(@NonNull View child, int left, int dx) {
+            return 0;
+        }
+
+        /**
+         * Restrict the motion of the dragged child view along the vertical axis.
+         * The default implementation does not allow vertical motion; the extending
+         * class must override this method and provide the desired clamping.
+         *
+         *
+         * @param child Child view being dragged
+         * @param top Attempted motion along the Y axis
+         * @param dy Proposed change in position for top
+         * @return The new clamped position for top
+         */
+        public int clampViewPositionVertical(@NonNull View child, int top, int dy) {
+            return 0;
+        }
+    }
+
+    /**
+     * Interpolator defining the animation curve for mScroller
+     */
+    private static final Interpolator sInterpolator = new Interpolator() {
+        @Override
+        public float getInterpolation(float t) {
+            t -= 1.0f;
+            return t * t * t * t * t + 1.0f;
+        }
+    };
+
+    private final Runnable mSetIdleRunnable = new Runnable() {
+        @Override
+        public void run() {
+            setDragState(STATE_IDLE);
+        }
+    };
+
+    /**
+     * Factory method to create a new ViewDragHelper.
+     *
+     * @param forParent Parent view to monitor
+     * @param cb Callback to provide information and receive events
+     * @return a new ViewDragHelper instance
+     */
+    public static ViewDragHelper create(@NonNull ViewGroup forParent, @NonNull Callback cb) {
+        return new ViewDragHelper(forParent.getContext(), forParent, cb);
+    }
+
+    /**
+     * Factory method to create a new ViewDragHelper.
+     *
+     * @param forParent Parent view to monitor
+     * @param sensitivity Multiplier for how sensitive the helper should be about detecting
+     *                    the start of a drag. Larger values are more sensitive. 1.0f is normal.
+     * @param cb Callback to provide information and receive events
+     * @return a new ViewDragHelper instance
+     */
+    public static ViewDragHelper create(@NonNull ViewGroup forParent, float sensitivity,
+            @NonNull Callback cb) {
+        final ViewDragHelper helper = create(forParent, cb);
+        helper.mTouchSlop = (int) (helper.mTouchSlop * (1 / sensitivity));
+        return helper;
+    }
+
+    /**
+     * Apps should use ViewDragHelper.create() to get a new instance.
+     * This will allow VDH to use internal compatibility implementations for different
+     * platform versions.
+     *
+     * @param context Context to initialize config-dependent params from
+     * @param forParent Parent view to monitor
+     */
+    private ViewDragHelper(@NonNull Context context, @NonNull ViewGroup forParent,
+            @NonNull Callback cb) {
+        if (forParent == null) {
+            throw new IllegalArgumentException("Parent view may not be null");
+        }
+        if (cb == null) {
+            throw new IllegalArgumentException("Callback may not be null");
+        }
+
+        mParentView = forParent;
+        mCallback = cb;
+
+        final ViewConfiguration vc = ViewConfiguration.get(context);
+        final float density = context.getResources().getDisplayMetrics().density;
+        mEdgeSize = (int) (EDGE_SIZE * density + 0.5f);
+
+        mTouchSlop = vc.getScaledTouchSlop();
+        mMaxVelocity = vc.getScaledMaximumFlingVelocity();
+        mMinVelocity = vc.getScaledMinimumFlingVelocity();
+        mScroller = new OverScroller(context, sInterpolator);
+    }
+
+    /**
+     * Set the minimum velocity that will be detected as having a magnitude greater than zero
+     * in pixels per second. Callback methods accepting a velocity will be clamped appropriately.
+     *
+     * @param minVel Minimum velocity to detect
+     */
+    public void setMinVelocity(float minVel) {
+        mMinVelocity = minVel;
+    }
+
+    /**
+     * Return the currently configured minimum velocity. Any flings with a magnitude less
+     * than this value in pixels per second. Callback methods accepting a velocity will receive
+     * zero as a velocity value if the real detected velocity was below this threshold.
+     *
+     * @return the minimum velocity that will be detected
+     */
+    public float getMinVelocity() {
+        return mMinVelocity;
+    }
+
+    /**
+     * Retrieve the current drag state of this helper. This will return one of
+     * {@link #STATE_IDLE}, {@link #STATE_DRAGGING} or {@link #STATE_SETTLING}.
+     * @return The current drag state
+     */
+    public int getViewDragState() {
+        return mDragState;
+    }
+
+    /**
+     * Enable edge tracking for the selected edges of the parent view.
+     * The callback's {@link Callback#onEdgeTouched(int, int)} and
+     * {@link Callback#onEdgeDragStarted(int, int)} methods will only be invoked
+     * for edges for which edge tracking has been enabled.
+     *
+     * @param edgeFlags Combination of edge flags describing the edges to watch
+     * @see #EDGE_LEFT
+     * @see #EDGE_TOP
+     * @see #EDGE_RIGHT
+     * @see #EDGE_BOTTOM
+     */
+    public void setEdgeTrackingEnabled(int edgeFlags) {
+        mTrackingEdges = edgeFlags;
+    }
+
+    /**
+     * Return the size of an edge. This is the range in pixels along the edges of this view
+     * that will actively detect edge touches or drags if edge tracking is enabled.
+     *
+     * @return The size of an edge in pixels
+     * @see #setEdgeTrackingEnabled(int)
+     */
+    @Px
+    public int getEdgeSize() {
+        return mEdgeSize;
+    }
+
+    /**
+     * Capture a specific child view for dragging within the parent. The callback will be notified
+     * but {@link Callback#tryCaptureView(android.view.View, int)} will not be asked permission to
+     * capture this view.
+     *
+     * @param childView Child view to capture
+     * @param activePointerId ID of the pointer that is dragging the captured child view
+     */
+    public void captureChildView(@NonNull View childView, int activePointerId) {
+        if (childView.getParent() != mParentView) {
+            throw new IllegalArgumentException("captureChildView: parameter must be a descendant "
+                    + "of the ViewDragHelper's tracked parent view (" + mParentView + ")");
+        }
+
+        mCapturedView = childView;
+        mActivePointerId = activePointerId;
+        mCallback.onViewCaptured(childView, activePointerId);
+        setDragState(STATE_DRAGGING);
+    }
+
+    /**
+     * @return The currently captured view, or null if no view has been captured.
+     */
+    @Nullable
+    public View getCapturedView() {
+        return mCapturedView;
+    }
+
+    /**
+     * @return The ID of the pointer currently dragging the captured view,
+     *         or {@link #INVALID_POINTER}.
+     */
+    public int getActivePointerId() {
+        return mActivePointerId;
+    }
+
+    /**
+     * @return The minimum distance in pixels that the user must travel to initiate a drag
+     */
+    @Px
+    public int getTouchSlop() {
+        return mTouchSlop;
+    }
+
+    /**
+     * The result of a call to this method is equivalent to
+     * {@link #processTouchEvent(android.view.MotionEvent)} receiving an ACTION_CANCEL event.
+     */
+    public void cancel() {
+        mActivePointerId = INVALID_POINTER;
+        clearMotionHistory();
+
+        if (mVelocityTracker != null) {
+            mVelocityTracker.recycle();
+            mVelocityTracker = null;
+        }
+    }
+
+    /**
+     * {@link #cancel()}, but also abort all motion in progress and snap to the end of any
+     * animation.
+     */
+    public void abort() {
+        cancel();
+        if (mDragState == STATE_SETTLING) {
+            final int oldX = mScroller.getCurrX();
+            final int oldY = mScroller.getCurrY();
+            mScroller.abortAnimation();
+            final int newX = mScroller.getCurrX();
+            final int newY = mScroller.getCurrY();
+            mCallback.onViewPositionChanged(mCapturedView, newX, newY, newX - oldX, newY - oldY);
+        }
+        setDragState(STATE_IDLE);
+    }
+
+    /**
+     * Animate the view <code>child</code> to the given (left, top) position.
+     * If this method returns true, the caller should invoke {@link #continueSettling(boolean)}
+     * on each subsequent frame to continue the motion until it returns false. If this method
+     * returns false there is no further work to do to complete the movement.
+     *
+     * <p>This operation does not count as a capture event, though {@link #getCapturedView()}
+     * will still report the sliding view while the slide is in progress.</p>
+     *
+     * @param child Child view to capture and animate
+     * @param finalLeft Final left position of child
+     * @param finalTop Final top position of child
+     * @return true if animation should continue through {@link #continueSettling(boolean)} calls
+     */
+    public boolean smoothSlideViewTo(@NonNull View child, int finalLeft, int finalTop) {
+        mCapturedView = child;
+        mActivePointerId = INVALID_POINTER;
+
+        boolean continueSliding = forceSettleCapturedViewAt(finalLeft, finalTop, 0, 0);
+        if (!continueSliding && mDragState == STATE_IDLE && mCapturedView != null) {
+            // If we're in an IDLE state to begin with and aren't moving anywhere, we
+            // end up having a non-null capturedView with an IDLE dragState
+            mCapturedView = null;
+        }
+
+        return continueSliding;
+    }
+
+    /**
+     * Settle the captured view at the given (left, top) position.
+     * The appropriate velocity from prior motion will be taken into account.
+     * If this method returns true, the caller should invoke {@link #continueSettling(boolean)}
+     * on each subsequent frame to continue the motion until it returns false. If this method
+     * returns false there is no further work to do to complete the movement.
+     *
+     * @param finalLeft Settled left edge position for the captured view
+     * @param finalTop Settled top edge position for the captured view
+     * @return true if animation should continue through {@link #continueSettling(boolean)} calls
+     */
+    public boolean settleCapturedViewAt(int finalLeft, int finalTop) {
+        if (!mReleaseInProgress) {
+            throw new IllegalStateException("Cannot settleCapturedViewAt outside of a call to "
+                    + "Callback#onViewReleased");
+        }
+
+        return forceSettleCapturedViewAt(finalLeft, finalTop,
+                (int) mVelocityTracker.getXVelocity(mActivePointerId),
+                (int) mVelocityTracker.getYVelocity(mActivePointerId));
+    }
+
+    /**
+     * Settle the captured view at the given (left, top) position.
+     *
+     * @param finalLeft Target left position for the captured view
+     * @param finalTop Target top position for the captured view
+     * @param xvel Horizontal velocity
+     * @param yvel Vertical velocity
+     * @return true if animation should continue through {@link #continueSettling(boolean)} calls
+     */
+    private boolean forceSettleCapturedViewAt(int finalLeft, int finalTop, int xvel, int yvel) {
+        final int startLeft = mCapturedView.getLeft();
+        final int startTop = mCapturedView.getTop();
+        final int dx = finalLeft - startLeft;
+        final int dy = finalTop - startTop;
+
+        if (dx == 0 && dy == 0) {
+            // Nothing to do. Send callbacks, be done.
+            mScroller.abortAnimation();
+            setDragState(STATE_IDLE);
+            return false;
+        }
+
+        final int duration = computeSettleDuration(mCapturedView, dx, dy, xvel, yvel);
+        mScroller.startScroll(startLeft, startTop, dx, dy, duration);
+
+        setDragState(STATE_SETTLING);
+        return true;
+    }
+
+    private int computeSettleDuration(View child, int dx, int dy, int xvel, int yvel) {
+        xvel = clampMag(xvel, (int) mMinVelocity, (int) mMaxVelocity);
+        yvel = clampMag(yvel, (int) mMinVelocity, (int) mMaxVelocity);
+        final int absDx = Math.abs(dx);
+        final int absDy = Math.abs(dy);
+        final int absXVel = Math.abs(xvel);
+        final int absYVel = Math.abs(yvel);
+        final int addedVel = absXVel + absYVel;
+        final int addedDistance = absDx + absDy;
+
+        final float xweight = xvel != 0 ? (float) absXVel / addedVel :
+                (float) absDx / addedDistance;
+        final float yweight = yvel != 0 ? (float) absYVel / addedVel :
+                (float) absDy / addedDistance;
+
+        int xduration = computeAxisDuration(dx, xvel, mCallback.getViewHorizontalDragRange(child));
+        int yduration = computeAxisDuration(dy, yvel, mCallback.getViewVerticalDragRange(child));
+
+        return (int) (xduration * xweight + yduration * yweight);
+    }
+
+    private int computeAxisDuration(int delta, int velocity, int motionRange) {
+        if (delta == 0) {
+            return 0;
+        }
+
+        final int width = mParentView.getWidth();
+        final int halfWidth = width / 2;
+        final float distanceRatio = Math.min(1f, (float) Math.abs(delta) / width);
+        final float distance = halfWidth + halfWidth
+                * distanceInfluenceForSnapDuration(distanceRatio);
+
+        int duration;
+        velocity = Math.abs(velocity);
+        if (velocity > 0) {
+            duration = 4 * Math.round(1000 * Math.abs(distance / velocity));
+        } else {
+            final float range = (float) Math.abs(delta) / motionRange;
+            duration = (int) ((range + 1) * BASE_SETTLE_DURATION);
+        }
+        return Math.min(duration, MAX_SETTLE_DURATION);
+    }
+
+    /**
+     * Clamp the magnitude of value for absMin and absMax.
+     * If the value is below the minimum, it will be clamped to zero.
+     * If the value is above the maximum, it will be clamped to the maximum.
+     *
+     * @param value Value to clamp
+     * @param absMin Absolute value of the minimum significant value to return
+     * @param absMax Absolute value of the maximum value to return
+     * @return The clamped value with the same sign as <code>value</code>
+     */
+    private int clampMag(int value, int absMin, int absMax) {
+        final int absValue = Math.abs(value);
+        if (absValue < absMin) return 0;
+        if (absValue > absMax) return value > 0 ? absMax : -absMax;
+        return value;
+    }
+
+    /**
+     * Clamp the magnitude of value for absMin and absMax.
+     * If the value is below the minimum, it will be clamped to zero.
+     * If the value is above the maximum, it will be clamped to the maximum.
+     *
+     * @param value Value to clamp
+     * @param absMin Absolute value of the minimum significant value to return
+     * @param absMax Absolute value of the maximum value to return
+     * @return The clamped value with the same sign as <code>value</code>
+     */
+    private float clampMag(float value, float absMin, float absMax) {
+        final float absValue = Math.abs(value);
+        if (absValue < absMin) return 0;
+        if (absValue > absMax) return value > 0 ? absMax : -absMax;
+        return value;
+    }
+
+    private float distanceInfluenceForSnapDuration(float f) {
+        f -= 0.5f; // center the values about 0.
+        f *= 0.3f * (float) Math.PI / 2.0f;
+        return (float) Math.sin(f);
+    }
+
+    /**
+     * Settle the captured view based on standard free-moving fling behavior.
+     * The caller should invoke {@link #continueSettling(boolean)} on each subsequent frame
+     * to continue the motion until it returns false.
+     *
+     * @param minLeft Minimum X position for the view's left edge
+     * @param minTop Minimum Y position for the view's top edge
+     * @param maxLeft Maximum X position for the view's left edge
+     * @param maxTop Maximum Y position for the view's top edge
+     */
+    public void flingCapturedView(int minLeft, int minTop, int maxLeft, int maxTop) {
+        if (!mReleaseInProgress) {
+            throw new IllegalStateException("Cannot flingCapturedView outside of a call to "
+                    + "Callback#onViewReleased");
+        }
+
+        mScroller.fling(mCapturedView.getLeft(), mCapturedView.getTop(),
+                (int) mVelocityTracker.getXVelocity(mActivePointerId),
+                (int) mVelocityTracker.getYVelocity(mActivePointerId),
+                minLeft, maxLeft, minTop, maxTop);
+
+        setDragState(STATE_SETTLING);
+    }
+
+    /**
+     * Move the captured settling view by the appropriate amount for the current time.
+     * If <code>continueSettling</code> returns true, the caller should call it again
+     * on the next frame to continue.
+     *
+     * @param deferCallbacks true if state callbacks should be deferred via posted message.
+     *                       Set this to true if you are calling this method from
+     *                       {@link android.view.View#computeScroll()} or similar methods
+     *                       invoked as part of layout or drawing.
+     * @return true if settle is still in progress
+     */
+    public boolean continueSettling(boolean deferCallbacks) {
+        if (mDragState == STATE_SETTLING) {
+            boolean keepGoing = mScroller.computeScrollOffset();
+            final int x = mScroller.getCurrX();
+            final int y = mScroller.getCurrY();
+            final int dx = x - mCapturedView.getLeft();
+            final int dy = y - mCapturedView.getTop();
+
+            if (dx != 0) {
+                ViewCompat.offsetLeftAndRight(mCapturedView, dx);
+            }
+            if (dy != 0) {
+                ViewCompat.offsetTopAndBottom(mCapturedView, dy);
+            }
+
+            if (dx != 0 || dy != 0) {
+                mCallback.onViewPositionChanged(mCapturedView, x, y, dx, dy);
+            }
+
+            if (keepGoing && x == mScroller.getFinalX() && y == mScroller.getFinalY()) {
+                // Close enough. The interpolator/scroller might think we're still moving
+                // but the user sure doesn't.
+                mScroller.abortAnimation();
+                keepGoing = false;
+            }
+
+            if (!keepGoing) {
+                if (deferCallbacks) {
+                    mParentView.post(mSetIdleRunnable);
+                } else {
+                    setDragState(STATE_IDLE);
+                }
+            }
+        }
+
+        return mDragState == STATE_SETTLING;
+    }
+
+    /**
+     * Like all callback events this must happen on the UI thread, but release
+     * involves some extra semantics. During a release (mReleaseInProgress)
+     * is the only time it is valid to call {@link #settleCapturedViewAt(int, int)}
+     * or {@link #flingCapturedView(int, int, int, int)}.
+     */
+    private void dispatchViewReleased(float xvel, float yvel) {
+        mReleaseInProgress = true;
+        mCallback.onViewReleased(mCapturedView, xvel, yvel);
+        mReleaseInProgress = false;
+
+        if (mDragState == STATE_DRAGGING) {
+            // onViewReleased didn't call a method that would have changed this. Go idle.
+            setDragState(STATE_IDLE);
+        }
+    }
+
+    private void clearMotionHistory() {
+        if (mInitialMotionX == null) {
+            return;
+        }
+        Arrays.fill(mInitialMotionX, 0);
+        Arrays.fill(mInitialMotionY, 0);
+        Arrays.fill(mLastMotionX, 0);
+        Arrays.fill(mLastMotionY, 0);
+        Arrays.fill(mInitialEdgesTouched, 0);
+        Arrays.fill(mEdgeDragsInProgress, 0);
+        Arrays.fill(mEdgeDragsLocked, 0);
+        mPointersDown = 0;
+    }
+
+    private void clearMotionHistory(int pointerId) {
+        if (mInitialMotionX == null || !isPointerDown(pointerId)) {
+            return;
+        }
+        mInitialMotionX[pointerId] = 0;
+        mInitialMotionY[pointerId] = 0;
+        mLastMotionX[pointerId] = 0;
+        mLastMotionY[pointerId] = 0;
+        mInitialEdgesTouched[pointerId] = 0;
+        mEdgeDragsInProgress[pointerId] = 0;
+        mEdgeDragsLocked[pointerId] = 0;
+        mPointersDown &= ~(1 << pointerId);
+    }
+
+    private void ensureMotionHistorySizeForId(int pointerId) {
+        if (mInitialMotionX == null || mInitialMotionX.length <= pointerId) {
+            float[] imx = new float[pointerId + 1];
+            float[] imy = new float[pointerId + 1];
+            float[] lmx = new float[pointerId + 1];
+            float[] lmy = new float[pointerId + 1];
+            int[] iit = new int[pointerId + 1];
+            int[] edip = new int[pointerId + 1];
+            int[] edl = new int[pointerId + 1];
+
+            if (mInitialMotionX != null) {
+                System.arraycopy(mInitialMotionX, 0, imx, 0, mInitialMotionX.length);
+                System.arraycopy(mInitialMotionY, 0, imy, 0, mInitialMotionY.length);
+                System.arraycopy(mLastMotionX, 0, lmx, 0, mLastMotionX.length);
+                System.arraycopy(mLastMotionY, 0, lmy, 0, mLastMotionY.length);
+                System.arraycopy(mInitialEdgesTouched, 0, iit, 0, mInitialEdgesTouched.length);
+                System.arraycopy(mEdgeDragsInProgress, 0, edip, 0, mEdgeDragsInProgress.length);
+                System.arraycopy(mEdgeDragsLocked, 0, edl, 0, mEdgeDragsLocked.length);
+            }
+
+            mInitialMotionX = imx;
+            mInitialMotionY = imy;
+            mLastMotionX = lmx;
+            mLastMotionY = lmy;
+            mInitialEdgesTouched = iit;
+            mEdgeDragsInProgress = edip;
+            mEdgeDragsLocked = edl;
+        }
+    }
+
+    private void saveInitialMotion(float x, float y, int pointerId) {
+        ensureMotionHistorySizeForId(pointerId);
+        mInitialMotionX[pointerId] = mLastMotionX[pointerId] = x;
+        mInitialMotionY[pointerId] = mLastMotionY[pointerId] = y;
+        mInitialEdgesTouched[pointerId] = getEdgesTouched((int) x, (int) y);
+        mPointersDown |= 1 << pointerId;
+    }
+
+    private void saveLastMotion(MotionEvent ev) {
+        final int pointerCount = ev.getPointerCount();
+        for (int i = 0; i < pointerCount; i++) {
+            final int pointerId = ev.getPointerId(i);
+            // If pointer is invalid then skip saving on ACTION_MOVE.
+            if (!isValidPointerForActionMove(pointerId)) {
+                continue;
+            }
+            final float x = ev.getX(i);
+            final float y = ev.getY(i);
+            mLastMotionX[pointerId] = x;
+            mLastMotionY[pointerId] = y;
+        }
+    }
+
+    /**
+     * Check if the given pointer ID represents a pointer that is currently down (to the best
+     * of the ViewDragHelper's knowledge).
+     *
+     * <p>The state used to report this information is populated by the methods
+     * {@link #shouldInterceptTouchEvent(android.view.MotionEvent)} or
+     * {@link #processTouchEvent(android.view.MotionEvent)}. If one of these methods has not
+     * been called for all relevant MotionEvents to track, the information reported
+     * by this method may be stale or incorrect.</p>
+     *
+     * @param pointerId pointer ID to check; corresponds to IDs provided by MotionEvent
+     * @return true if the pointer with the given ID is still down
+     */
+    public boolean isPointerDown(int pointerId) {
+        return (mPointersDown & 1 << pointerId) != 0;
+    }
+
+    void setDragState(int state) {
+        mParentView.removeCallbacks(mSetIdleRunnable);
+        if (mDragState != state) {
+            mDragState = state;
+            mCallback.onViewDragStateChanged(state);
+            if (mDragState == STATE_IDLE) {
+                mCapturedView = null;
+            }
+        }
+    }
+
+    /**
+     * Attempt to capture the view with the given pointer ID. The callback will be involved.
+     * This will put us into the "dragging" state. If we've already captured this view with
+     * this pointer this method will immediately return true without consulting the callback.
+     *
+     * @param toCapture View to capture
+     * @param pointerId Pointer to capture with
+     * @return true if capture was successful
+     */
+    boolean tryCaptureViewForDrag(View toCapture, int pointerId) {
+        if (toCapture == mCapturedView && mActivePointerId == pointerId) {
+            // Already done!
+            return true;
+        }
+        if (toCapture != null && mCallback.tryCaptureView(toCapture, pointerId)) {
+            mActivePointerId = pointerId;
+            captureChildView(toCapture, pointerId);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Tests scrollability within child views of v given a delta of dx.
+     *
+     * @param v View to test for horizontal scrollability
+     * @param checkV Whether the view v passed should itself be checked for scrollability (true),
+     *               or just its children (false).
+     * @param dx Delta scrolled in pixels along the X axis
+     * @param dy Delta scrolled in pixels along the Y axis
+     * @param x X coordinate of the active touch point
+     * @param y Y coordinate of the active touch point
+     * @return true if child views of v can be scrolled by delta of dx.
+     */
+    protected boolean canScroll(@NonNull View v, boolean checkV, int dx, int dy, int x, int y) {
+        if (v instanceof ViewGroup) {
+            final ViewGroup group = (ViewGroup) v;
+            final int scrollX = v.getScrollX();
+            final int scrollY = v.getScrollY();
+            final int count = group.getChildCount();
+            // Count backwards - let topmost views consume scroll distance first.
+            for (int i = count - 1; i >= 0; i--) {
+                // TODO: Add versioned support here for transformed views.
+                // This will not work for transformed views in Honeycomb+
+                final View child = group.getChildAt(i);
+                if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight()
+                        && y + scrollY >= child.getTop() && y + scrollY < child.getBottom()
+                        && canScroll(child, true, dx, dy, x + scrollX - child.getLeft(),
+                                y + scrollY - child.getTop())) {
+                    return true;
+                }
+            }
+        }
+
+        return checkV && (v.canScrollHorizontally(-dx) || v.canScrollVertically(-dy));
+    }
+
+    /**
+     * Check if this event as provided to the parent view's onInterceptTouchEvent should
+     * cause the parent to intercept the touch event stream.
+     *
+     * @param ev MotionEvent provided to onInterceptTouchEvent
+     * @return true if the parent view should return true from onInterceptTouchEvent
+     */
+    public boolean shouldInterceptTouchEvent(@NonNull MotionEvent ev) {
+        final int action = ev.getActionMasked();
+        final int actionIndex = ev.getActionIndex();
+
+        if (action == MotionEvent.ACTION_DOWN) {
+            // Reset things for a new event stream, just in case we didn't get
+            // the whole previous stream.
+            cancel();
+        }
+
+        if (mVelocityTracker == null) {
+            mVelocityTracker = VelocityTracker.obtain();
+        }
+        mVelocityTracker.addMovement(ev);
+
+        switch (action) {
+            case MotionEvent.ACTION_DOWN: {
+                final float x = ev.getX();
+                final float y = ev.getY();
+                final int pointerId = ev.getPointerId(0);
+                saveInitialMotion(x, y, pointerId);
+
+                final View toCapture = findTopChildUnder((int) x, (int) y);
+
+                // Catch a settling view if possible.
+                if (toCapture == mCapturedView && mDragState == STATE_SETTLING) {
+                    tryCaptureViewForDrag(toCapture, pointerId);
+                }
+
+                final int edgesTouched = mInitialEdgesTouched[pointerId];
+                if ((edgesTouched & mTrackingEdges) != 0) {
+                    mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId);
+                }
+                break;
+            }
+
+            case MotionEvent.ACTION_POINTER_DOWN: {
+                final int pointerId = ev.getPointerId(actionIndex);
+                final float x = ev.getX(actionIndex);
+                final float y = ev.getY(actionIndex);
+
+                saveInitialMotion(x, y, pointerId);
+
+                // A ViewDragHelper can only manipulate one view at a time.
+                if (mDragState == STATE_IDLE) {
+                    final int edgesTouched = mInitialEdgesTouched[pointerId];
+                    if ((edgesTouched & mTrackingEdges) != 0) {
+                        mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId);
+                    }
+                } else if (mDragState == STATE_SETTLING) {
+                    // Catch a settling view if possible.
+                    final View toCapture = findTopChildUnder((int) x, (int) y);
+                    if (toCapture == mCapturedView) {
+                        tryCaptureViewForDrag(toCapture, pointerId);
+                    }
+                }
+                break;
+            }
+
+            case MotionEvent.ACTION_MOVE: {
+                if (mInitialMotionX == null || mInitialMotionY == null) break;
+
+                // First to cross a touch slop over a draggable view wins. Also report edge drags.
+                final int pointerCount = ev.getPointerCount();
+                for (int i = 0; i < pointerCount; i++) {
+                    final int pointerId = ev.getPointerId(i);
+
+                    // If pointer is invalid then skip the ACTION_MOVE.
+                    if (!isValidPointerForActionMove(pointerId)) continue;
+
+                    final float x = ev.getX(i);
+                    final float y = ev.getY(i);
+                    final float dx = x - mInitialMotionX[pointerId];
+                    final float dy = y - mInitialMotionY[pointerId];
+
+                    final View toCapture = findTopChildUnder((int) x, (int) y);
+                    final boolean pastSlop = toCapture != null && checkTouchSlop(toCapture, dx, dy);
+                    if (pastSlop) {
+                        // check the callback's
+                        // getView[Horizontal|Vertical]DragRange methods to know
+                        // if you can move at all along an axis, then see if it
+                        // would clamp to the same value. If you can't move at
+                        // all in every dimension with a nonzero range, bail.
+                        final int oldLeft = toCapture.getLeft();
+                        final int targetLeft = oldLeft + (int) dx;
+                        final int newLeft = mCallback.clampViewPositionHorizontal(toCapture,
+                                targetLeft, (int) dx);
+                        final int oldTop = toCapture.getTop();
+                        final int targetTop = oldTop + (int) dy;
+                        final int newTop = mCallback.clampViewPositionVertical(toCapture, targetTop,
+                                (int) dy);
+                        final int hDragRange = mCallback.getViewHorizontalDragRange(toCapture);
+                        final int vDragRange = mCallback.getViewVerticalDragRange(toCapture);
+                        if ((hDragRange == 0 || (hDragRange > 0 && newLeft == oldLeft))
+                                && (vDragRange == 0 || (vDragRange > 0 && newTop == oldTop))) {
+                            break;
+                        }
+                    }
+                    reportNewEdgeDrags(dx, dy, pointerId);
+                    if (mDragState == STATE_DRAGGING) {
+                        // Callback might have started an edge drag
+                        break;
+                    }
+
+                    if (pastSlop && tryCaptureViewForDrag(toCapture, pointerId)) {
+                        break;
+                    }
+                }
+                saveLastMotion(ev);
+                break;
+            }
+
+            case MotionEvent.ACTION_POINTER_UP: {
+                final int pointerId = ev.getPointerId(actionIndex);
+                clearMotionHistory(pointerId);
+                break;
+            }
+
+            case MotionEvent.ACTION_UP:
+            case MotionEvent.ACTION_CANCEL: {
+                cancel();
+                break;
+            }
+        }
+
+        return mDragState == STATE_DRAGGING;
+    }
+
+    /**
+     * Process a touch event received by the parent view. This method will dispatch callback events
+     * as needed before returning. The parent view's onTouchEvent implementation should call this.
+     *
+     * @param ev The touch event received by the parent view
+     */
+    public void processTouchEvent(@NonNull MotionEvent ev) {
+        final int action = ev.getActionMasked();
+        final int actionIndex = ev.getActionIndex();
+
+        if (action == MotionEvent.ACTION_DOWN) {
+            // Reset things for a new event stream, just in case we didn't get
+            // the whole previous stream.
+            cancel();
+        }
+
+        if (mVelocityTracker == null) {
+            mVelocityTracker = VelocityTracker.obtain();
+        }
+        mVelocityTracker.addMovement(ev);
+
+        switch (action) {
+            case MotionEvent.ACTION_DOWN: {
+                final float x = ev.getX();
+                final float y = ev.getY();
+                final int pointerId = ev.getPointerId(0);
+                final View toCapture = findTopChildUnder((int) x, (int) y);
+
+                saveInitialMotion(x, y, pointerId);
+
+                // Since the parent is already directly processing this touch event,
+                // there is no reason to delay for a slop before dragging.
+                // Start immediately if possible.
+                tryCaptureViewForDrag(toCapture, pointerId);
+
+                final int edgesTouched = mInitialEdgesTouched[pointerId];
+                if ((edgesTouched & mTrackingEdges) != 0) {
+                    mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId);
+                }
+                break;
+            }
+
+            case MotionEvent.ACTION_POINTER_DOWN: {
+                final int pointerId = ev.getPointerId(actionIndex);
+                final float x = ev.getX(actionIndex);
+                final float y = ev.getY(actionIndex);
+
+                saveInitialMotion(x, y, pointerId);
+
+                // A ViewDragHelper can only manipulate one view at a time.
+                if (mDragState == STATE_IDLE) {
+                    // If we're idle we can do anything! Treat it like a normal down event.
+
+                    final View toCapture = findTopChildUnder((int) x, (int) y);
+                    tryCaptureViewForDrag(toCapture, pointerId);
+
+                    final int edgesTouched = mInitialEdgesTouched[pointerId];
+                    if ((edgesTouched & mTrackingEdges) != 0) {
+                        mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId);
+                    }
+                } else if (isCapturedViewUnder((int) x, (int) y)) {
+                    // We're still tracking a captured view. If the same view is under this
+                    // point, we'll swap to controlling it with this pointer instead.
+                    // (This will still work if we're "catching" a settling view.)
+
+                    tryCaptureViewForDrag(mCapturedView, pointerId);
+                }
+                break;
+            }
+
+            case MotionEvent.ACTION_MOVE: {
+                if (mDragState == STATE_DRAGGING) {
+                    // If pointer is invalid then skip the ACTION_MOVE.
+                    if (!isValidPointerForActionMove(mActivePointerId)) break;
+
+                    final int index = ev.findPointerIndex(mActivePointerId);
+                    final float x = ev.getX(index);
+                    final float y = ev.getY(index);
+                    final int idx = (int) (x - mLastMotionX[mActivePointerId]);
+                    final int idy = (int) (y - mLastMotionY[mActivePointerId]);
+
+                    dragTo(mCapturedView.getLeft() + idx, mCapturedView.getTop() + idy, idx, idy);
+
+                    saveLastMotion(ev);
+                } else {
+                    // Check to see if any pointer is now over a draggable view.
+                    final int pointerCount = ev.getPointerCount();
+                    for (int i = 0; i < pointerCount; i++) {
+                        final int pointerId = ev.getPointerId(i);
+
+                        // If pointer is invalid then skip the ACTION_MOVE.
+                        if (!isValidPointerForActionMove(pointerId)) continue;
+
+                        final float x = ev.getX(i);
+                        final float y = ev.getY(i);
+                        final float dx = x - mInitialMotionX[pointerId];
+                        final float dy = y - mInitialMotionY[pointerId];
+
+                        reportNewEdgeDrags(dx, dy, pointerId);
+                        if (mDragState == STATE_DRAGGING) {
+                            // Callback might have started an edge drag.
+                            break;
+                        }
+
+                        final View toCapture = findTopChildUnder((int) x, (int) y);
+                        if (checkTouchSlop(toCapture, dx, dy)
+                                && tryCaptureViewForDrag(toCapture, pointerId)) {
+                            break;
+                        }
+                    }
+                    saveLastMotion(ev);
+                }
+                break;
+            }
+
+            case MotionEvent.ACTION_POINTER_UP: {
+                final int pointerId = ev.getPointerId(actionIndex);
+                if (mDragState == STATE_DRAGGING && pointerId == mActivePointerId) {
+                    // Try to find another pointer that's still holding on to the captured view.
+                    int newActivePointer = INVALID_POINTER;
+                    final int pointerCount = ev.getPointerCount();
+                    for (int i = 0; i < pointerCount; i++) {
+                        final int id = ev.getPointerId(i);
+                        if (id == mActivePointerId) {
+                            // This one's going away, skip.
+                            continue;
+                        }
+
+                        final float x = ev.getX(i);
+                        final float y = ev.getY(i);
+                        if (findTopChildUnder((int) x, (int) y) == mCapturedView
+                                && tryCaptureViewForDrag(mCapturedView, id)) {
+                            newActivePointer = mActivePointerId;
+                            break;
+                        }
+                    }
+
+                    if (newActivePointer == INVALID_POINTER) {
+                        // We didn't find another pointer still touching the view, release it.
+                        releaseViewForPointerUp();
+                    }
+                }
+                clearMotionHistory(pointerId);
+                break;
+            }
+
+            case MotionEvent.ACTION_UP: {
+                if (mDragState == STATE_DRAGGING) {
+                    releaseViewForPointerUp();
+                }
+                cancel();
+                break;
+            }
+
+            case MotionEvent.ACTION_CANCEL: {
+                if (mDragState == STATE_DRAGGING) {
+                    dispatchViewReleased(0, 0);
+                }
+                cancel();
+                break;
+            }
+        }
+    }
+
+    private void reportNewEdgeDrags(float dx, float dy, int pointerId) {
+        int dragsStarted = 0;
+        if (checkNewEdgeDrag(dx, dy, pointerId, EDGE_LEFT)) {
+            dragsStarted |= EDGE_LEFT;
+        }
+        if (checkNewEdgeDrag(dy, dx, pointerId, EDGE_TOP)) {
+            dragsStarted |= EDGE_TOP;
+        }
+        if (checkNewEdgeDrag(dx, dy, pointerId, EDGE_RIGHT)) {
+            dragsStarted |= EDGE_RIGHT;
+        }
+        if (checkNewEdgeDrag(dy, dx, pointerId, EDGE_BOTTOM)) {
+            dragsStarted |= EDGE_BOTTOM;
+        }
+
+        if (dragsStarted != 0) {
+            mEdgeDragsInProgress[pointerId] |= dragsStarted;
+            mCallback.onEdgeDragStarted(dragsStarted, pointerId);
+        }
+    }
+
+    private boolean checkNewEdgeDrag(float delta, float odelta, int pointerId, int edge) {
+        final float absDelta = Math.abs(delta);
+        final float absODelta = Math.abs(odelta);
+
+        if ((mInitialEdgesTouched[pointerId] & edge) != edge  || (mTrackingEdges & edge) == 0
+                || (mEdgeDragsLocked[pointerId] & edge) == edge
+                || (mEdgeDragsInProgress[pointerId] & edge) == edge
+                || (absDelta <= mTouchSlop && absODelta <= mTouchSlop)) {
+            return false;
+        }
+        if (absDelta < absODelta * 0.5f && mCallback.onEdgeLock(edge)) {
+            mEdgeDragsLocked[pointerId] |= edge;
+            return false;
+        }
+        return (mEdgeDragsInProgress[pointerId] & edge) == 0 && absDelta > mTouchSlop;
+    }
+
+    /**
+     * Check if we've crossed a reasonable touch slop for the given child view.
+     * If the child cannot be dragged along the horizontal or vertical axis, motion
+     * along that axis will not count toward the slop check.
+     *
+     * @param child Child to check
+     * @param dx Motion since initial position along X axis
+     * @param dy Motion since initial position along Y axis
+     * @return true if the touch slop has been crossed
+     */
+    private boolean checkTouchSlop(View child, float dx, float dy) {
+        if (child == null) {
+            return false;
+        }
+        final boolean checkHorizontal = mCallback.getViewHorizontalDragRange(child) > 0;
+        final boolean checkVertical = mCallback.getViewVerticalDragRange(child) > 0;
+
+        if (checkHorizontal && checkVertical) {
+            return dx * dx + dy * dy > mTouchSlop * mTouchSlop;
+        } else if (checkHorizontal) {
+            return Math.abs(dx) > mTouchSlop;
+        } else if (checkVertical) {
+            return Math.abs(dy) > mTouchSlop;
+        }
+        return false;
+    }
+
+    /**
+     * Check if any pointer tracked in the current gesture has crossed
+     * the required slop threshold.
+     *
+     * <p>This depends on internal state populated by
+     * {@link #shouldInterceptTouchEvent(android.view.MotionEvent)} or
+     * {@link #processTouchEvent(android.view.MotionEvent)}. You should only rely on
+     * the results of this method after all currently available touch data
+     * has been provided to one of these two methods.</p>
+     *
+     * @param directions Combination of direction flags, see {@link #DIRECTION_HORIZONTAL},
+     *                   {@link #DIRECTION_VERTICAL}, {@link #DIRECTION_ALL}
+     * @return true if the slop threshold has been crossed, false otherwise
+     */
+    public boolean checkTouchSlop(int directions) {
+        final int count = mInitialMotionX.length;
+        for (int i = 0; i < count; i++) {
+            if (checkTouchSlop(directions, i)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Check if the specified pointer tracked in the current gesture has crossed
+     * the required slop threshold.
+     *
+     * <p>This depends on internal state populated by
+     * {@link #shouldInterceptTouchEvent(android.view.MotionEvent)} or
+     * {@link #processTouchEvent(android.view.MotionEvent)}. You should only rely on
+     * the results of this method after all currently available touch data
+     * has been provided to one of these two methods.</p>
+     *
+     * @param directions Combination of direction flags, see {@link #DIRECTION_HORIZONTAL},
+     *                   {@link #DIRECTION_VERTICAL}, {@link #DIRECTION_ALL}
+     * @param pointerId ID of the pointer to slop check as specified by MotionEvent
+     * @return true if the slop threshold has been crossed, false otherwise
+     */
+    public boolean checkTouchSlop(int directions, int pointerId) {
+        if (!isPointerDown(pointerId)) {
+            return false;
+        }
+
+        final boolean checkHorizontal = (directions & DIRECTION_HORIZONTAL) == DIRECTION_HORIZONTAL;
+        final boolean checkVertical = (directions & DIRECTION_VERTICAL) == DIRECTION_VERTICAL;
+
+        final float dx = mLastMotionX[pointerId] - mInitialMotionX[pointerId];
+        final float dy = mLastMotionY[pointerId] - mInitialMotionY[pointerId];
+
+        if (checkHorizontal && checkVertical) {
+            return dx * dx + dy * dy > mTouchSlop * mTouchSlop;
+        } else if (checkHorizontal) {
+            return Math.abs(dx) > mTouchSlop;
+        } else if (checkVertical) {
+            return Math.abs(dy) > mTouchSlop;
+        }
+        return false;
+    }
+
+    /**
+     * Check if any of the edges specified were initially touched in the currently active gesture.
+     * If there is no currently active gesture this method will return false.
+     *
+     * @param edges Edges to check for an initial edge touch. See {@link #EDGE_LEFT},
+     *              {@link #EDGE_TOP}, {@link #EDGE_RIGHT}, {@link #EDGE_BOTTOM} and
+     *              {@link #EDGE_ALL}
+     * @return true if any of the edges specified were initially touched in the current gesture
+     */
+    public boolean isEdgeTouched(int edges) {
+        final int count = mInitialEdgesTouched.length;
+        for (int i = 0; i < count; i++) {
+            if (isEdgeTouched(edges, i)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Check if any of the edges specified were initially touched by the pointer with
+     * the specified ID. If there is no currently active gesture or if there is no pointer with
+     * the given ID currently down this method will return false.
+     *
+     * @param edges Edges to check for an initial edge touch. See {@link #EDGE_LEFT},
+     *              {@link #EDGE_TOP}, {@link #EDGE_RIGHT}, {@link #EDGE_BOTTOM} and
+     *              {@link #EDGE_ALL}
+     * @return true if any of the edges specified were initially touched in the current gesture
+     */
+    public boolean isEdgeTouched(int edges, int pointerId) {
+        return isPointerDown(pointerId) && (mInitialEdgesTouched[pointerId] & edges) != 0;
+    }
+
+    private void releaseViewForPointerUp() {
+        mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity);
+        final float xvel = clampMag(
+                mVelocityTracker.getXVelocity(mActivePointerId),
+                mMinVelocity, mMaxVelocity);
+        final float yvel = clampMag(
+                mVelocityTracker.getYVelocity(mActivePointerId),
+                mMinVelocity, mMaxVelocity);
+        dispatchViewReleased(xvel, yvel);
+    }
+
+    private void dragTo(int left, int top, int dx, int dy) {
+        int clampedX = left;
+        int clampedY = top;
+        final int oldLeft = mCapturedView.getLeft();
+        final int oldTop = mCapturedView.getTop();
+        if (dx != 0) {
+            clampedX = mCallback.clampViewPositionHorizontal(mCapturedView, left, dx);
+            ViewCompat.offsetLeftAndRight(mCapturedView, clampedX - oldLeft);
+        }
+        if (dy != 0) {
+            clampedY = mCallback.clampViewPositionVertical(mCapturedView, top, dy);
+            ViewCompat.offsetTopAndBottom(mCapturedView, clampedY - oldTop);
+        }
+
+        if (dx != 0 || dy != 0) {
+            final int clampedDx = clampedX - oldLeft;
+            final int clampedDy = clampedY - oldTop;
+            mCallback.onViewPositionChanged(mCapturedView, clampedX, clampedY,
+                    clampedDx, clampedDy);
+        }
+    }
+
+    /**
+     * Determine if the currently captured view is under the given point in the
+     * parent view's coordinate system. If there is no captured view this method
+     * will return false.
+     *
+     * @param x X position to test in the parent's coordinate system
+     * @param y Y position to test in the parent's coordinate system
+     * @return true if the captured view is under the given point, false otherwise
+     */
+    public boolean isCapturedViewUnder(int x, int y) {
+        return isViewUnder(mCapturedView, x, y);
+    }
+
+    /**
+     * Determine if the supplied view is under the given point in the
+     * parent view's coordinate system.
+     *
+     * @param view Child view of the parent to hit test
+     * @param x X position to test in the parent's coordinate system
+     * @param y Y position to test in the parent's coordinate system
+     * @return true if the supplied view is under the given point, false otherwise
+     */
+    public boolean isViewUnder(@Nullable View view, int x, int y) {
+        if (view == null) {
+            return false;
+        }
+        return x >= view.getLeft()
+                && x < view.getRight()
+                && y >= view.getTop()
+                && y < view.getBottom();
+    }
+
+    /**
+     * Find the topmost child under the given point within the parent view's coordinate system.
+     * The child order is determined using {@link Callback#getOrderedChildIndex(int)}.
+     *
+     * @param x X position to test in the parent's coordinate system
+     * @param y Y position to test in the parent's coordinate system
+     * @return The topmost child view under (x, y) or null if none found.
+     */
+    @Nullable
+    public View findTopChildUnder(int x, int y) {
+        final int childCount = mParentView.getChildCount();
+        for (int i = childCount - 1; i >= 0; i--) {
+            final View child = mParentView.getChildAt(mCallback.getOrderedChildIndex(i));
+            if (x >= child.getLeft() && x < child.getRight()
+                    && y >= child.getTop() && y < child.getBottom()) {
+                return child;
+            }
+        }
+        return null;
+    }
+
+    private int getEdgesTouched(int x, int y) {
+        int result = 0;
+
+        if (x < mParentView.getLeft() + mEdgeSize) result |= EDGE_LEFT;
+        if (y < mParentView.getTop() + mEdgeSize) result |= EDGE_TOP;
+        if (x > mParentView.getRight() - mEdgeSize) result |= EDGE_RIGHT;
+        if (y > mParentView.getBottom() - mEdgeSize) result |= EDGE_BOTTOM;
+
+        return result;
+    }
+
+    private boolean isValidPointerForActionMove(int pointerId) {
+        if (!isPointerDown(pointerId)) {
+            Log.e(TAG, "Ignoring pointerId=" + pointerId + " because ACTION_DOWN was not received "
+                    + "for this pointer before ACTION_MOVE. It likely happened because "
+                    + " ViewDragHelper did not receive all the events in the event stream.");
+            return false;
+        }
+        return true;
+    }
+}
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/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/AndroidManifest.xml b/dynamic-animation/src/main/AndroidManifest.xml
similarity index 100%
rename from dynamic-animation/AndroidManifest.xml
rename to dynamic-animation/src/main/AndroidManifest.xml
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/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/AndroidManifest.xml b/emoji/appcompat/src/main/AndroidManifest.xml
similarity index 100%
rename from emoji/appcompat/AndroidManifest.xml
rename to emoji/appcompat/src/main/AndroidManifest.xml
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/AndroidManifest.xml b/emoji/bundled/src/main/AndroidManifest.xml
similarity index 100%
rename from emoji/bundled/AndroidManifest.xml
rename to emoji/bundled/src/main/AndroidManifest.xml
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/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/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/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/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/AndroidManifest.xml b/graphics/drawable/animated/src/main/AndroidManifest.xml
similarity index 100%
rename from graphics/drawable/animated/AndroidManifest.xml
rename to graphics/drawable/animated/src/main/AndroidManifest.xml
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/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/textclassifier/src/androidTest/NO_DOCS b/heifwriter/src/androidTest/NO_DOCS
similarity index 100%
rename from textclassifier/src/androidTest/NO_DOCS
rename to heifwriter/src/androidTest/NO_DOCS
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/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/jetifier/core/build.gradle b/jetifier/jetifier/core/build.gradle
index 2bf4d08..683a020 100644
--- a/jetifier/jetifier/core/build.gradle
+++ b/jetifier/jetifier/core/build.gradle
@@ -30,7 +30,7 @@
     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")
 }
 
 supportLibrary {
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 aa2e1e3..7bf3ba0 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
@@ -24,6 +24,7 @@
 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.PomDependency
 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
@@ -74,9 +75,10 @@
 
         /**
          * Creates a new instance of the [Processor].
-         * [config] Transformation configuration
-         * [reversedMode] Whether the processor should run in reversed mode
-         * [rewritingSupportLib] Whether we are rewriting the support library itself
+         *
+         * @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,
@@ -90,7 +92,7 @@
                     restrictToPackagePrefixes = listOf(REVERSE_RESTRICT_TO_PACKAGE),
                     rewriteRules = config.rewriteRules,
                     slRules = config.slRules,
-                    pomRewriteRules = emptyList(), // TODO: This will need a new set of rules
+                    pomRewriteRules = emptySet(), // TODO: This will need a new set of rules
                     typesMap = config.typesMap.reverseMapOrDie(),
                     proGuardMap = config.proGuardMap.reverseMapOrDie(),
                     packageMap = config.packageMap.reverse()
@@ -110,17 +112,26 @@
 
     /**
      * 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,
-            outputIsDir: Boolean
-    ): TransformationResult {
+            outputIsDir: Boolean,
+            copyUnmodifiedLibsAlso: Boolean = true
+    ): Set<File> {
         // 0) Validate arguments
         if (!outputIsDir && inputLibraries.size > 1) {
             throw IllegalArgumentException("Cannot process more than 1 library (" + inputLibraries +
@@ -148,19 +159,53 @@
         // 4) Transform the previously discovered POM files
         transformPomFiles(pomFiles)
 
-        // 5) Repackage the libraries back to archives
-        val outputLibraries = libraries.map {
-            if (outputIsDir) {
-                it.writeSelfToDir(outputPath)
-            } else {
-                it.writeSelfToFile(outputPath)
+        // 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()
+            .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)
+    }
+
+    /**
+     * Maps the given dependency (in form of groupId:artifactId:version) to a new set of
+     * dependencies. Used for mapping of old support library artifacts to jetpack ones.
+     *
+     * @return set of new dependencies. Can be empty which means the given dependency should be
+     * removed without replacement. Returns null in case a mapping was not found which means that
+     * the given artifact was unknown.
+     */
+    fun mapDependency(depNotation: String): Set<String>? {
+        val parts = depNotation.split(":")
+        val inputDependency = PomDependency(
+            groupId = parts[0],
+            artifactId = parts[1],
+            version = parts[2])
+
+        // TODO: We ignore version check for now
+        val resultRule = context.config.pomRewriteRules
+            .firstOrNull { it.matches(inputDependency) } ?: return null
+
+        return resultRule.to
+            .map { it.toStringNotation() }
+            .toSet()
     }
 
     private fun loadLibraries(inputLibraries: Iterable<File>): List<Archive> {
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 bac2ffb..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,6 +48,9 @@
 
     override val fileName: String = relativePath.fileName.toString()
 
+    override val wasChanged: Boolean
+        get() = files.any { it.wasChanged }
+
     override fun accept(visitor: ArchiveItemVisitor) {
         visitor.visit(this)
     }
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 8443773..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,7 +23,7 @@
 /**
  * Represents a file in the archive that is not an archive.
  */
-class ArchiveFile(relativePath: Path, var data: ByteArray) : ArchiveItem {
+class ArchiveFile(relativePath: Path, data: ByteArray) : ArchiveItem {
 
     override var relativePath = relativePath
         private set
@@ -31,6 +31,12 @@
     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)
     }
@@ -41,7 +47,16 @@
     }
 
     fun updateRelativePath(newRelativePath: Path) {
-        this.relativePath = newRelativePath
-        this.fileName = relativePath.fileName.toString()
+        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 007130d..dc2f861 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
@@ -36,13 +36,25 @@
  * 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 packageMap: PackageMap = PackageMap(PackageMap.DEFAULT_RULES)) {
+    val restrictToPackagePrefixes: List<String>,
+    val rewriteRules: List<RewriteRule>,
+    val slRules: List<RewriteRule>,
+    val pomRewriteRules: Set<PomRewriteRule>,
+    val typesMap: TypesMap,
+    val proGuardMap: ProGuardTypesMap,
+    val packageMap: PackageMap = PackageMap(PackageMap.DEFAULT_RULES)
+) {
+
+    init {
+        // Verify pom rules
+        val testSet = mutableSetOf<String>()
+        pomRewriteRules.forEach {
+            val raw = "${it.from.groupId}:${it.from.artifactId}"
+            if (!testSet.add(raw)) {
+                throw IllegalArgumentException("Artifact '$raw' is defined twice in pom rules!")
+            }
+        }
+    }
 
     companion object {
         /** Path to the default config file located within the jar file. */
@@ -86,15 +98,16 @@
             val mappings: TypesMap.JsonData? = null,
 
             @SerializedName("proGuardMap")
-            val proGuardMap: ProGuardTypesMap.JsonData? = null) {
-
+            val proGuardMap: ProGuardTypesMap.JsonData? = null
+    ) {
         /** Creates instance of [Config] */
         fun toConfig(): Config {
+
             return Config(
                 restrictToPackagePrefixes = restrictToPackages.filterNotNull(),
                 rewriteRules = rules.filterNotNull().map { it.toRule() },
                 slRules = slRules?.filterNotNull()?.map { it.toRule() } ?: listOf(),
-                pomRewriteRules = pomRules.filterNotNull().map { it.toRule() },
+                pomRewriteRules = pomRules.filterNotNull().map { it.toRule() }.toSet(),
                 typesMap = mappings?.toMappings() ?: TypesMap.EMPTY,
                 proGuardMap = proGuardMap?.toMappings() ?: ProGuardTypesMap.EMPTY
             )
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 296ce49..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
@@ -25,9 +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()
 
@@ -35,11 +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/CoreRemapperImpl.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/bytecode/CoreRemapperImpl.kt
index 2ff0081..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
@@ -28,7 +28,10 @@
 /**
  * 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): ClassRemapper {
-        return ClassRemapper(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
         }
@@ -64,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()
         }
@@ -85,6 +91,7 @@
 
         val result = rewriteType(type)
         if (result != type) {
+            changesDone = true
             return path.fileSystem.getPath(result.fullName + ".class")
         }
 
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
index 3220dae..333d776 100644
--- 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
@@ -61,6 +61,6 @@
             return
         }
 
-        file.data = to.toByteArray()
+        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/PomDependency.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/pom/PomDependency.kt
index 1622fd7..8e480d0 100644
--- a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/pom/PomDependency.kt
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/pom/PomDependency.kt
@@ -27,10 +27,10 @@
  */
 data class PomDependency(
         @SerializedName("groupId")
-        val groupId: String? = null,
+        val groupId: String?,
 
         @SerializedName("artifactId")
-        val artifactId: String? = null,
+        val artifactId: String?,
 
         @SerializedName("version")
         var version: String? = null,
@@ -55,15 +55,15 @@
         /**
          * Creates a new [PomDependency] from the given XML [Element].
          */
-        fun fromXmlElement(node: Element, properties: Map<String, String>) : PomDependency {
-            var groupId : String? = null
-            var artifactId : String? = null
-            var version : String? = null
-            var classifier : String? = null
-            var type : String? = null
-            var scope : String? = null
-            var systemPath : String? = null
-            var optional : String? = null
+        fun fromXmlElement(node: Element, properties: Map<String, String>): PomDependency {
+            var groupId: String? = null
+            var artifactId: String? = null
+            var version: String? = null
+            var classifier: String? = null
+            var type: String? = null
+            var scope: String? = null
+            var systemPath: String? = null
+            var optional: String? = null
 
             for (childNode in node.children) {
                 when (childNode.name) {
@@ -88,7 +88,6 @@
                     systemPath = systemPath,
                     optional = optional)
         }
-
     }
 
     init {
@@ -100,7 +99,7 @@
     /**
      * Whether this dependency should be skipped from the rewriting process
      */
-    fun shouldSkipRewrite() : Boolean {
+    fun shouldSkipRewrite(): Boolean {
         return scope != null && scope.toLowerCase() == "test"
     }
 
@@ -108,7 +107,7 @@
      * Returns a new dependency created by taking all the items from the [input] dependency and then
      * overwriting these with all of its non-null items.
      */
-    fun rewrite(input: PomDependency) : PomDependency {
+    fun rewrite(input: PomDependency): PomDependency {
         return PomDependency(
             groupId = groupId ?: input.groupId,
             artifactId = artifactId ?: input.artifactId,
@@ -124,7 +123,7 @@
     /**
      * Transforms the current data into XML '<dependency>' node.
      */
-    fun toXmlElement(document: Document) : Element {
+    fun toXmlElement(document: Document): Element {
         val node = Element("dependency")
         node.namespace = document.rootElement.namespace
 
@@ -139,4 +138,11 @@
 
         return node
     }
+
+    /**
+     * Returns the dependency in format "groupId:artifactId:version".
+     */
+    fun toStringNotation(): String {
+        return "$groupId:$artifactId:$version"
+    }
 }
\ 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..bdde62e 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: Set<PomRewriteRule>): Boolean {
         if (dependenciesGroup == null) {
             // Nothing to validate as this file has no dependencies section
             return true
@@ -78,7 +78,7 @@
      *
      * Changes are not saved back until requested.
      */
-    fun applyRules(rules: List<PomRewriteRule>) {
+    fun applyRules(rules: Set<PomRewriteRule>) {
         if (dependenciesGroup == null) {
             // Nothing to transform as this file has no dependencies section
             return
@@ -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/pom/PomRewriteRule.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/pom/PomRewriteRule.kt
index 070a640..2ae6449 100644
--- a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/pom/PomRewriteRule.kt
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/pom/PomRewriteRule.kt
@@ -25,16 +25,35 @@
  * Any dependency that is matched against [from] should be rewritten to list of the dependencies
  * defined in [to].
  */
-data class PomRewriteRule(val from: PomDependency, val to: List<PomDependency>) {
+data class PomRewriteRule(val from: PomDependency, val to: Set<PomDependency>) {
+
+    init {
+        validate(from, checkVersion = false)
+        to.forEach { validate(it, checkVersion = true) }
+    }
 
     companion object {
-        val TAG : String = "PomRule"
+        val TAG: String = "PomRule"
+
+        private fun validate(dep: PomDependency, checkVersion: Boolean) {
+            if (dep.groupId == null || dep.groupId.isEmpty()) {
+                throw IllegalArgumentException("GroupId is missing in the POM rule!")
+            }
+
+            if (dep.artifactId == null || dep.artifactId.isEmpty()) {
+                throw IllegalArgumentException("ArtifactId is missing in the POM rule!")
+            }
+
+            if (checkVersion && (dep.version == null || dep.version!!.isEmpty())) {
+                throw IllegalArgumentException("Version is missing in the POM rule!")
+            }
+        }
     }
 
     /**
      * Validates that the given [input] dependency has a valid version.
      */
-    fun validateVersion(input: PomDependency, document: PomDocument? = null) : Boolean {
+    fun validateVersion(input: PomDependency, document: PomDocument? = null): Boolean {
         if (from.version == null || input.version == null) {
             return true
         }
@@ -59,7 +78,7 @@
      * Version entry can be actually quite complicated, see the full documentation at:
      * https://maven.apache.org/pom.html#Dependencies
      */
-    private fun areVersionsMatching(ourVersion: String, version: String) : Boolean {
+    private fun areVersionsMatching(ourVersion: String, version: String): Boolean {
         if (version == "latest" || version == "release") {
             return true
         }
@@ -75,29 +94,28 @@
         return ourVersion == version
     }
 
-    fun matches(input: PomDependency) : Boolean {
+    fun matches(input: PomDependency): Boolean {
         return input.artifactId == from.artifactId && input.groupId == from.groupId
     }
 
     /** Returns JSON data model of this class */
-    fun toJson() : PomRewriteRule.JsonData {
+    fun toJson(): PomRewriteRule.JsonData {
         return PomRewriteRule.JsonData(from, to)
     }
 
-
     /**
      * JSON data model for [PomRewriteRule].
      */
     data class JsonData(
-            @SerializedName("from")
-            val from: PomDependency,
-            @SerializedName("to")
-            val to: List<PomDependency>)  {
+        @SerializedName("from")
+        val from: PomDependency,
+        @SerializedName("to")
+        val to: Set<PomDependency>
+    ) {
 
         /** Creates instance of [PomRewriteRule] */
-        fun toRule() : PomRewriteRule {
-            return PomRewriteRule(from, to.filterNotNull())
+        fun toRule(): PomRewriteRule {
+            return PomRewriteRule(from, to.filterNotNull().toSet())
         }
     }
-
 }
\ No newline at end of file
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/resource/XmlResourcesTransformer.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/resource/XmlResourcesTransformer.kt
index 4f81c71..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
@@ -89,7 +89,7 @@
         }
 
         if (changesDone) {
-            file.data = sb.toString().toByteArray(charset)
+            file.setNewData(sb.toString().toByteArray(charset))
         }
     }
 
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..1e77bcb
--- /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 = emptySet(),
+        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 = setOf(
+            PomRewriteRule(
+                PomDependency(
+                    groupId = "supportGroup", artifactId = "supportArtifact", version = "4.0"),
+                setOf(
+                    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 97cfc2f..49ef6f8 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
@@ -23,34 +23,34 @@
 
     @Test fun parseConfig_validInput() {
         val confStr =
-                "{\n" +
-                "    restrictToPackagePrefixes: [\"android/support/\"],\n" +
-                "    # Sample comment \n" +
-                "    rules: [\n" +
-                "        {\n" +
-                "            from: \"android/support/v14/preferences/(.*)\",\n" +
-                "            to: \"android/jetpack/prefs/main/{0}\"\n" +
-                "        },\n" +
-                "        {\n" +
-                "            from: \"android/support/v14/preferences/(.*)\",\n" +
-                "            to: \"android/jetpack/prefs/main/{0}\",\n" +
-                "            fieldSelectors: [\"dialog_(.*)\"]\n" +
-                "        }\n" +
-                "    ],\n" +
-                "    pomRules: [\n" +
-                "        {\n" +
-                "            from: {groupId: \"g\", artifactId: \"a\", version: \"1.0\"},\n" +
-                "            to: [\n" +
-                "                {groupId: \"g\", artifactId: \"a\", version: \"2.0\"} \n" +
-                "            ]\n" +
-                "        }\n" +
-                "    ],\n" +
-                "   proGuardMap: {\n" +
-                "       rules: {\n" +
-                "           \"android/support/**\": \"androidx/**\"\n" +
-                "       }\n" +
-                "    }" +
-                "}"
+            "{\n" +
+            "    restrictToPackagePrefixes: [\"android/support/\"],\n" +
+            "    # Sample comment \n" +
+            "    rules: [\n" +
+            "        {\n" +
+            "            from: \"android/support/v14/preferences/(.*)\",\n" +
+            "            to: \"android/jetpack/prefs/main/{0}\"\n" +
+            "        },\n" +
+            "        {\n" +
+            "            from: \"android/support/v14/preferences/(.*)\",\n" +
+            "            to: \"android/jetpack/prefs/main/{0}\",\n" +
+            "            fieldSelectors: [\"dialog_(.*)\"]\n" +
+            "        }\n" +
+            "    ],\n" +
+            "    pomRules: [\n" +
+            "        {\n" +
+            "            from: {groupId: \"g\", artifactId: \"a\", version: \"1.0\"},\n" +
+            "            to: [\n" +
+            "                {groupId: \"g\", artifactId: \"a\", version: \"2.0\"} \n" +
+            "            ]\n" +
+            "        }\n" +
+            "    ],\n" +
+            "   proGuardMap: {\n" +
+            "       rules: {\n" +
+            "           \"android/support/**\": \"androidx/**\"\n" +
+            "       }\n" +
+            "    }" +
+            "}"
 
         val config = ConfigParser.parseFromString(confStr)
 
@@ -59,5 +59,76 @@
         Truth.assertThat(config.rewriteRules.size).isEqualTo(2)
         Truth.assertThat(config.proGuardMap.rules.size).isEqualTo(1)
     }
-}
 
+    @Test(expected = IllegalArgumentException::class)
+    fun parseConfig_pomMissingGroup_shouldFail() {
+        val confStr =
+            "{\n" +
+            "    restrictToPackagePrefixes: [\"android/support/\"],\n" +
+            "    rules: [\n" +
+            "    ],\n" +
+            "    pomRules: [\n" +
+            "        {\n" +
+            "            from: {artifactId: \"a\", version: \"1.0\"},\n" +
+            "            to: []\n" +
+            "        }\n" +
+            "    ]\n" +
+            "}"
+        ConfigParser.parseFromString(confStr)
+    }
+
+    @Test(expected = IllegalArgumentException::class)
+    fun parseConfig_pomMissingArtifact_shouldFail() {
+        val confStr =
+            "{\n" +
+            "    restrictToPackagePrefixes: [\"android/support/\"],\n" +
+            "    rules: [\n" +
+            "    ],\n" +
+            "    pomRules: [\n" +
+            "        {\n" +
+            "            from: {groupId: \"g\", version: \"1.0\"},\n" +
+            "            to: []\n" +
+            "        }\n" +
+            "    ]\n" +
+            "}"
+        ConfigParser.parseFromString(confStr)
+    }
+
+    @Test(expected = IllegalArgumentException::class)
+    fun parseConfig_pomMissingVersion_shouldFail() {
+        val confStr =
+            "{\n" +
+            "    restrictToPackagePrefixes: [\"android/support/\"],\n" +
+            "    rules: [\n" +
+            "    ],\n" +
+            "    pomRules: [\n" +
+            "        {\n" +
+            "            from: {artifactId: \"a\", groupId: \"g\"},\n" +
+            "            to: [{artifactId: \"a\", groupId: \"g\"}]\n" +
+            "        }\n" +
+            "    ]\n" +
+            "}"
+        ConfigParser.parseFromString(confStr)
+    }
+
+    @Test(expected = IllegalArgumentException::class)
+    fun parseConfig_duplicity_shouldFail() {
+        val confStr =
+            "{\n" +
+                "    restrictToPackagePrefixes: [\"android/support/\"],\n" +
+                "    rules: [\n" +
+                "    ],\n" +
+                "    pomRules: [\n" +
+                "        {\n" +
+                "            from: {artifactId: \"a\", groupId: \"g\", version: \"1.0\"},\n" +
+                "            to: []\n" +
+                "        },\n" +
+                "        {\n" +
+                "            from: {artifactId: \"a\", groupId: \"g\", version: \"2.0\"},\n" +
+                "            to: []\n" +
+                "        }\n" +
+                "    ]\n" +
+                "}"
+        ConfigParser.parseFromString(confStr)
+    }
+}
\ No newline at end of file
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 6f4eb59..9f56676 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
@@ -162,7 +162,7 @@
                         restrictToPackagePrefixes = prefixes,
                         rewriteRules = rules,
                         slRules = emptyList(),
-                        pomRewriteRules = emptyList(),
+                        pomRewriteRules = emptySet(),
                         typesMap = TypesMap.EMPTY,
                         proGuardMap = ProGuardTypesMap.EMPTY)
                     val scanner = MapGeneratorRemapper(config)
diff --git a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/DependencyMappingTest.kt b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/DependencyMappingTest.kt
new file mode 100644
index 0000000..3499fef
--- /dev/null
+++ b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/DependencyMappingTest.kt
@@ -0,0 +1,102 @@
+package android.support.tools.jetifier.core.transform
+
+import android.support.tools.jetifier.core.Processor
+import android.support.tools.jetifier.core.config.Config
+import android.support.tools.jetifier.core.map.TypesMap
+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
+
+class DependencyMappingTest {
+
+    @Test
+    fun mapTest_oneToOne_shouldMap() {
+        MappingTester
+            .testRewrite(
+                from = "hello:world:1.0.0",
+                to = setOf("hi:all:2.0.0"),
+                rules = setOf(
+                    PomRewriteRule(
+                        from = PomDependency(groupId = "hello", artifactId = "world"),
+                        to = setOf(
+                            PomDependency(groupId = "hi", artifactId = "all", version = "2.0.0")
+                        )
+                    ))
+            )
+    }
+
+    @Test
+    fun mapTest_oneToTwo_shouldMap() {
+        MappingTester
+            .testRewrite(
+                from = "hello:world:1.0.0",
+                to = setOf("hi:all:2.0.0", "hey:all:3.0.0"),
+                rules = setOf(
+                    PomRewriteRule(
+                        from = PomDependency(groupId = "hello", artifactId = "world"),
+                        to = setOf(
+                            PomDependency(groupId = "hi", artifactId = "all", version = "2.0.0"),
+                            PomDependency(groupId = "hey", artifactId = "all", version = "3.0.0")
+                        )
+                    ))
+            )
+    }
+
+    @Test
+    fun mapTest_oneToNone_shouldMapToEmpty() {
+        MappingTester
+            .testRewrite(
+                from = "hello:world:1.0.0",
+                to = setOf(),
+                rules = setOf(
+                    PomRewriteRule(
+                        from = PomDependency(groupId = "hello", artifactId = "world"),
+                        to = setOf()
+                    ))
+            )
+    }
+
+    @Test
+    fun mapTest_oneToNull_ruleNotFound_returnNull() {
+        MappingTester
+            .testRewrite(
+                from = "hello:world:1.0.0",
+                to = null,
+                rules = setOf(
+                    PomRewriteRule(
+                        from = PomDependency(groupId = "hello", artifactId = "me", version = "1.0"),
+                        to = setOf()
+                    ))
+            )
+    }
+
+    object MappingTester {
+
+        fun testRewrite(
+            from: String,
+            to: Set<String>?,
+            rules: Set<PomRewriteRule>
+        ) {
+            val config = Config(
+                restrictToPackagePrefixes = emptyList(),
+                rewriteRules = emptyList(),
+                slRules = emptyList(),
+                pomRewriteRules = rules,
+                typesMap = TypesMap.EMPTY,
+                proGuardMap = ProGuardTypesMap.EMPTY,
+                packageMap = PackageMap.EMPTY
+            )
+
+            val processor = Processor.createProcessor(config)
+            val result = processor.mapDependency(from)
+
+            if (to == null) {
+                Truth.assertThat(result).isNull()
+            } else {
+                Truth.assertThat(result).containsExactlyElementsIn(to)
+            }
+        }
+    }
+}
\ No newline at end of file
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
index 3b189e6..0d08b02 100644
--- 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
@@ -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.core.transform.bytecode
 
 import android.support.tools.jetifier.core.Processor
@@ -31,7 +47,7 @@
                 RewriteRule("android/support/v7/preference/R(.*)", "ignore"),
                 RewriteRule("android/support/v4/(.*)", "ignore")
             ),
-            pomRewriteRules = emptyList(),
+            pomRewriteRules = emptySet(),
             typesMap = TypesMap(mapOf(
                 "android/support/v7/preference/Preference"
                     to "androidx/support/preference/Preference",
@@ -85,10 +101,10 @@
         val inputFile = File(javaClass.getResource(inputZipPath).file)
 
         val tempDir = createTempDir()
-        val result = processor.transform(setOf(inputFile), tempDir.toPath(), true)
+        val resultFiles = processor.transform(setOf(inputFile), tempDir.toPath(), true)
 
-        Truth.assertThat(result.filesToAdd).hasSize(1)
-        testArchivesAreSame(result.filesToAdd.first(),
+        Truth.assertThat(resultFiles).hasSize(1)
+        testArchivesAreSame(resultFiles.first(),
             File(javaClass.getResource(expectedZipPath).file))
 
         tempDir.delete()
@@ -106,10 +122,10 @@
         val inputFile = File(javaClass.getResource(inputZipPath).file)
 
         val tempDir = createTempDir()
-        val result = processor.transform(setOf(inputFile), tempDir.toPath(), true)
+        val resultFiles = processor.transform(setOf(inputFile), tempDir.toPath(), true)
 
-        Truth.assertThat(result.filesToAdd).hasSize(1)
-        testArchivesAreSame(result.filesToAdd.first(),
+        Truth.assertThat(resultFiles).hasSize(1)
+        testArchivesAreSame(resultFiles.first(),
             File(javaClass.getResource(expectedZipPath).file))
 
         tempDir.delete()
@@ -129,15 +145,15 @@
             rewritingSupportLib = true)
         val inputFile = File(javaClass.getResource(inputZipPath).file)
         val tempDir = createTempDir()
-        val result = processor.transform(setOf(inputFile), tempDir.toPath(), true)
+        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 result2 = processor2.transform(setOf(result.filesToAdd.first()), tempDir.toPath(), true)
+        val resultFiles2 = processor2.transform(setOf(resultFiles.first()), tempDir.toPath(), true)
 
-        testArchivesAreSame(result2.filesToAdd.first(),
+        testArchivesAreSame(resultFiles2.first(),
             File(javaClass.getResource(inputZipPath).file))
 
         tempDir.delete()
@@ -154,10 +170,10 @@
         val inputFile = File(javaClass.getResource(inputZipPath).file)
 
         val tempDir = createTempDir()
-        val result = processor.transform(setOf(inputFile), tempDir.toPath(), true)
+        val resultFiles = processor.transform(setOf(inputFile), tempDir.toPath(), true)
 
-        Truth.assertThat(result.filesToAdd).hasSize(1)
-        testArchivesAreSame(result.filesToAdd.first(),
+        Truth.assertThat(resultFiles).hasSize(1)
+        testArchivesAreSame(resultFiles.first(),
             File(javaClass.getResource(inputZipPath).file))
 
         tempDir.delete()
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
index db6cd21..c88c08d 100644
--- 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
@@ -103,7 +103,7 @@
             restrictToPackagePrefixes = emptyList(),
             rewriteRules = emptyList(),
             slRules = emptyList(),
-            pomRewriteRules = emptyList(),
+            pomRewriteRules = emptySet(),
             packageMap = PackageMap.EMPTY,
             typesMap = TypesMap.EMPTY,
             proGuardMap = ProGuardTypesMap.EMPTY
diff --git a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/pom/PomDocumentTest.kt b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/pom/PomDocumentTest.kt
index d55687f..2913ede 100644
--- a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/pom/PomDocumentTest.kt
+++ b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/pom/PomDocumentTest.kt
@@ -37,7 +37,7 @@
             "      <optional>true</optional>\n" +
             "    </dependency>\n" +
             "  </dependencies>",
-            rules = listOf()
+            rules = emptySet()
         )
     }
 
@@ -65,12 +65,12 @@
             "      <systemPath>test/test</systemPath>\n" +
             "    </dependency>\n" +
             "  </dependencies>",
-            rules = listOf(
+            rules = setOf(
                 PomRewriteRule(
                     PomDependency(
                         groupId = "supportGroup", artifactId = "supportArtifact",
                         version =  "4.0"),
-                    listOf(
+                    setOf(
                         PomDependency(
                             groupId = "testGroup", artifactId = "testArtifact",
                             version = "1.0")
@@ -91,12 +91,12 @@
             "      <scope>test</scope>\n" +
             "    </dependency>\n" +
             "  </dependencies>",
-            rules = listOf(
+            rules = setOf(
                 PomRewriteRule(
                     PomDependency(
                         groupId = "supportGroup", artifactId = "supportArtifact",
                         version =  "4.0"),
-                    listOf(
+                    setOf(
                         PomDependency(
                             groupId = "testGroup", artifactId = "testArtifact",
                             version = "1.0")
@@ -116,12 +116,12 @@
             "      <version>4.0</version>\n" +
             "    </dependency>\n" +
             "  </dependencies>",
-            rules = listOf(
+            rules = setOf(
                 PomRewriteRule(
                     PomDependency(
                         groupId = "supportGroup", artifactId = "supportArtifact2",
                         version =  "4.0"),
-                    listOf(
+                    setOf(
                         PomDependency(
                             groupId = "testGroup", artifactId = "testArtifact",
                             version = "1.0")
@@ -163,12 +163,12 @@
             "      <type>compile</type>\n" +
             "    </dependency>\n" +
             "  </dependencies>",
-            rules = listOf(
+            rules = setOf(
                 PomRewriteRule(
                     PomDependency(
                         groupId = "supportGroup", artifactId = "supportArtifact",
                         version =  "4.0"),
-                    listOf(
+                    setOf(
                         PomDependency(
                             groupId = "testGroup", artifactId = "testArtifact",
                             version = "1.0")
@@ -201,12 +201,12 @@
             "      <version>2.0</version>\n" +
             "    </dependency>\n" +
             "  </dependencies>",
-            rules = listOf(
+            rules = setOf(
                 PomRewriteRule(
                     PomDependency(
                         groupId = "supportGroup", artifactId = "supportArtifact",
                         version =  "4.0"),
-                    listOf(
+                    setOf(
                         PomDependency(
                             groupId = "testGroup", artifactId = "testArtifact",
                             version = "1.0"),
@@ -246,12 +246,12 @@
             "      <version>2.0</version>\n" +
             "    </dependency>\n" +
             "  </dependencies>",
-            rules = listOf(
+            rules = setOf(
                 PomRewriteRule(
                     PomDependency(
                         groupId = "supportGroup", artifactId = "supportArtifact",
                         version =  "4.0"),
-                    listOf(
+                    setOf(
                         PomDependency(
                             groupId = "testGroup", artifactId = "testArtifact",
                             version = "1.0"),
@@ -264,7 +264,7 @@
                     PomDependency(
                         groupId = "supportGroup", artifactId = "supportArtifact2",
                         version =  "4.0"),
-                    listOf(
+                    setOf(
                         PomDependency(
                             groupId = "testGroup", artifactId = "testArtifact",
                             version = "1.0"),
@@ -304,12 +304,12 @@
             "      <optional>true</optional>\n" +
             "    </dependency>\n" +
             "  </dependencies>",
-            rules = listOf(
+            rules = setOf(
                 PomRewriteRule(
                     PomDependency(
                         groupId = "supportGroup", artifactId = "supportArtifact",
                         version =  "4.0"),
-                    listOf(
+                    setOf(
                         PomDependency(
                             groupId = "testGroup", artifactId = "testArtifact",
                             version = "1.0")
@@ -357,11 +357,11 @@
     }
 
 
-    private fun testRewriteToTheSame(givenAndExpectedXml: String, rules: List<PomRewriteRule>) {
+    private fun testRewriteToTheSame(givenAndExpectedXml: String, rules: Set<PomRewriteRule>) {
         testRewrite(givenAndExpectedXml, givenAndExpectedXml, rules)
     }
 
-    private fun testRewrite(givenXml: String, expectedXml : String, rules: List<PomRewriteRule>) {
+    private fun testRewrite(givenXml: String, expectedXml : String, rules: Set<PomRewriteRule>) {
         val given =
             "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
             "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" " +
diff --git a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/pom/PomRewriteRuleTest.kt b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/pom/PomRewriteRuleTest.kt
index 34ebd04..94ed6e3 100644
--- a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/pom/PomRewriteRuleTest.kt
+++ b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/pom/PomRewriteRuleTest.kt
@@ -21,7 +21,8 @@
 
 class PomRewriteRuleTest {
 
-    @Test fun versions_nullInRule_match() {
+    @Test(expected = IllegalArgumentException::class)
+    fun versions_nullInRule_match() {
         testVersionsMatch(
             ruleVersion = null,
             pomVersion = "27.0.0"
@@ -35,7 +36,8 @@
         )
     }
 
-    @Test fun versions_nullBoth_match() {
+    @Test(expected = IllegalArgumentException::class)
+    fun versions_nullBoth_match() {
         testVersionsMatch(
             ruleVersion = null,
             pomVersion = null
@@ -120,19 +122,19 @@
     }
 
     private fun testVersionsMatch(ruleVersion: String?, pomVersion: String?) {
-        val from = PomDependency(version = ruleVersion)
-        val pom = PomDependency(version = pomVersion)
+        val from = PomDependency(groupId = "g", artifactId = "a", version = ruleVersion)
+        val pom = PomDependency(groupId = "g", artifactId = "a", version = pomVersion)
 
-        val rule = PomRewriteRule(from, listOf(from))
+        val rule = PomRewriteRule(from, setOf(from))
 
         Truth.assertThat(rule.validateVersion(pom)).isTrue()
     }
 
     private fun testVersionsDoNotMatch(ruleVersion: String?, pomVersion: String?) {
-        val from = PomDependency(version = ruleVersion)
-        val pom = PomDependency(version = pomVersion)
+        val from = PomDependency(groupId = "g", artifactId = "a", version = ruleVersion)
+        val pom = PomDependency(groupId = "g", artifactId = "a", version = pomVersion)
 
-        val rule = PomRewriteRule(from, listOf(from))
+        val rule = PomRewriteRule(from, setOf(from))
 
         Truth.assertThat(rule.validateVersion(pom)).isFalse()
     }
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 37075d3..d4acfb6 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
@@ -75,7 +75,7 @@
             restrictToPackagePrefixes = prefixes,
             rewriteRules = rewriteRules.map { RewriteRule(it.first, it.second) },
             slRules = emptyList(),
-            pomRewriteRules = emptyList(),
+            pomRewriteRules = emptySet(),
             typesMap = TypesMap(
                 types = javaTypes.map { JavaType(it.first) to JavaType(it.second) }.toMap()
             ),
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 4aaaae0..44f2ba4 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
@@ -325,7 +325,7 @@
             restrictToPackagePrefixes = prefixes,
             rewriteRules = emptyList(),
             slRules = emptyList(),
-            pomRewriteRules = emptyList(),
+            pomRewriteRules = emptySet(),
             typesMap = typeMap,
             proGuardMap = ProGuardTypesMap.EMPTY,
             packageMap = packageMap
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/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 082034fb..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,10 +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:")
@@ -46,7 +47,11 @@
             Log.logConsumer = JetifierLoggerAdapter(logger)
 
             val processor = Processor.createProcessor(config)
-            return processor.transform(filesToProcess, outputDir.toPath(), true)
+            return processor.transform(
+                filesToProcess,
+                outputDir.toPath(),
+                outputIsDir = true,
+                copyUnmodifiedLibsAlso = false)
         }
 
         fun shouldSkipArtifact(artifactId: String, groupId: String?, config: Config): Boolean {
diff --git a/jetifier/jetifier/preprocessor/build.gradle b/jetifier/jetifier/preprocessor/build.gradle
index a2b9eb2..893b763 100644
--- a/jetifier/jetifier/preprocessor/build.gradle
+++ b/jetifier/jetifier/preprocessor/build.gradle
@@ -19,8 +19,6 @@
     id("application")
 }
 
-version '1.0'
-
 mainClassName = "android.support.tools.jetifier.preprocessor.MainKt"
 
 dependencies {
diff --git a/jetifier/jetifier/preprocessor/scripts/processDefaultConfig.sh b/jetifier/jetifier/preprocessor/scripts/processDefaultConfig.sh
index 5ddc2df..d610408 100755
--- a/jetifier/jetifier/preprocessor/scripts/processDefaultConfig.sh
+++ b/jetifier/jetifier/preprocessor/scripts/processDefaultConfig.sh
@@ -25,11 +25,11 @@
 TEMP_LOG="$OUT_DIR/tempLog"
 
 JETIFIER_DIR="$ROOT_DIR/../.."
-BUILD_DIR="$ROOT_DIR/../../../../../../out/host/gradle/frameworks/support/jetifier"
+BUILD_DIR="$ROOT_DIR/../../../../../../out/host/gradle/frameworks/support"
 DEFAULT_CONFIG="$JETIFIER_DIR/core/src/main/resources/default.config"
 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"
+PREPROCESSOR_DISTRO_PATH="$BUILD_DIR/jetifier-preprocessor/build/distributions/jetifier-preprocessor.zip"
+PREPROCESSOR_BIN_PATH="$OUT_DIR/jetifier-preprocessor/bin/jetifier-preprocessor"
 SUPPORT_LIBS_BUILD_NUMBER="4560478"
 SUPPORT_LIBS_DOWNLOADED="$OUT_DIR/supportLibs/downloaded"
 SUPPORT_LIBS_UNPACKED="$OUT_DIR/supportLibs/unpacked"
@@ -56,7 +56,7 @@
 
 function buildProjectUsingGradle() {
 	cd $1
-	sh gradlew clean build $2 > $TEMP_LOG --stacktrace
+	sh gradlew :jetifier-preprocessor:clean :jetifier-preprocessor:uploadArchives $2 > $TEMP_LOG --stacktrace
 }
 
 
@@ -90,14 +90,14 @@
 getPreRenamedSupportLib
 
 printSectionStart "Preparing Jetifier"
-buildProjectUsingGradle $JETIFIER_DIR
+buildProjectUsingGradle $JETIFIER_DIR/../..
 echo "[OK] Clean build done"
 
 unzip $PREPROCESSOR_DISTRO_PATH -d $OUT_DIR > /dev/null
 echo "[OK] Copied & unziped jetifier preprocessor"
 
 printSectionStart "Preprocessing mappings on support libraries"
-sh $PREPROCESSOR_BIN_PATH -i "$SUPPORT_LIBS_UNPACKED" -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 || die
 echo "[OK] Done, config generated into $GENERATED_CONFIG"
 
 printSuccess
diff --git a/jetifier/jetifier/standalone/build.gradle b/jetifier/jetifier/standalone/build.gradle
index 8e1d9b9..3caa366 100644
--- a/jetifier/jetifier/standalone/build.gradle
+++ b/jetifier/jetifier/standalone/build.gradle
@@ -19,8 +19,6 @@
     id("application")
 }
 
-version '1.0'
-
 mainClassName = "android.support.tools.jetifier.standalone.MainKt"
 
 dependencies {
@@ -28,3 +26,10 @@
     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/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-af/strings.xml b/leanback/res/values-af/strings.xml
deleted file mode 100644
index a9ef3e8..0000000
--- a/leanback/res/values-af/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">"Navigasiekieslys"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Soekhandeling"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Soek"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Praat om te soek"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Deursoek <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Praat om <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> te deursoek"</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">"Speel"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Laat wag"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Vinnig vorentoe"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Spoel vorentoe %1$dX"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Spoel terug"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Spoel terug %1$dX"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Slaan volgende oor"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Slaan vorige oor"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Nog handelinge"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Ontkies laaik baie"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Kies laaik baie"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Ontkies laaik niks"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Kies laaik niks"</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Herhaal niks"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Herhaal alles"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Herhaal een"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Aktiveer skommel"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Deaktiveer skommel"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Aktiveer hoë gehalte"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Deaktiveer hoë gehalte"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Aktiveer onderskrifte"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Deaktiveer onderskrifte"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Voer prent in prentmodus in"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Mediakontroles word gewys"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Mediakontroles word versteek; druk D-paneel om te wys"</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Voltooi"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Gaan voort"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"MediaPlayer-foutkode %1$d ekstra %2$d"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"BEGIN HIER"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Volgende"</string>
-</resources>
diff --git a/leanback/res/values-am/strings.xml b/leanback/res/values-am/strings.xml
deleted file mode 100644
index 5ac73a5..0000000
--- a/leanback/res/values-am/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">"የMediaPlayer ስህተት ኮድ %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-ar/strings.xml b/leanback/res/values-ar/strings.xml
deleted file mode 100644
index 11f0d8c..0000000
--- a/leanback/res/values-ar/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">"‏رمز الخطأ في MediaPlayer %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-az/strings.xml b/leanback/res/values-az/strings.xml
deleted file mode 100644
index 7d5aa7b..0000000
--- a/leanback/res/values-az/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">"Naviqasiya menyusu"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Axtarış Fəaliyyəti"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Axtarış"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Axtarış üçün danışın"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Axtarış: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Axtarış üçün danışın: <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">"Oyun"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Pauza"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"İrəli ötürmə"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"İrəli sarı %1$dX"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Geri ötürmə"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Geri sarı %1$dX"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Növbətini atlayın"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Öncəkini atlayın"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Digər fəaliyyətlər"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Bəyənməkdən imtina edin"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Bəyənin"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Bəyənməməkdən imtina edin"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Bəyənməyin"</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Təkrarlanmasın"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Hamısını təkrarlayın"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Biri təkrarlansın"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Qarışdırma aktiv edilsin"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Qarışdırma deaktiv edilsin"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Yüksək keyfiyyəti aktiv edin"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Yüksək keyfiyyəti deaktiv edin"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Qapalı çəkilişi aktiv edin"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Qapalı çəkilişi deaktiv edin"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Şəkil içində Şəkil Rejiminə daxil olun"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Media idarəetmələri açıqdır"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Media idarəetmələri gizlidir, göstərmək üçün d-pad\'i basın"</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Bitir"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Davam edin"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"Media Pleyer xəta kodu %1$d əlavə %2$d"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"BAŞLAYIN"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Növbəti"</string>
-</resources>
diff --git a/leanback/res/values-b+sr+Latn/strings.xml b/leanback/res/values-b+sr+Latn/strings.xml
deleted file mode 100644
index 1a002b4..0000000
--- a/leanback/res/values-b+sr+Latn/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">"Meni za navigaciju"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Radnja pretrage"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Pretražite"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Govorite da biste pretraživali"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Pretražite <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Izgovorite da biste pretražili <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">"Pusti"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Pauziraj"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Premotaj unapred"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Premotaj unapred %1$dX"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Premotaj unazad"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Premotaj unazad %1$dX"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Preskoči sledeću"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Preskoči prethodnu"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Još radnji"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Opozovi izbor palca nagore"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Izaberi palac nagore"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Opozovi izbor palca nadole"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Izaberi palac nadole"</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Ne ponavljaj nijednu"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Ponovi sve"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Ponovi jednu"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Omogući nasumičnu reprodukciju"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Onemogući nasumičnu reprodukciju"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Omogući visok kvalitet"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Onemogući visok kvalitet"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Omogući titlove"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Onemogući titlove"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Uđi u režim Slika u slici"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Kontrole za medije su prikazane"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Kontrole za medije su skrivene, pritisnite kontrole za kretanje da biste ih prikazali"</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Dovrši"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Nastavi"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"Kôd greške MediaPlayer-a %1$d extra %2$d"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"ZAPOČNITE"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Dalje"</string>
-</resources>
diff --git a/leanback/res/values-be/strings.xml b/leanback/res/values-be/strings.xml
deleted file mode 100644
index 938722c..0000000
--- a/leanback/res/values-be/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">"Элементы кіравання мультымедыя схаваны. Каб паказаць іх, націсніце пераключальнік напрамкаў"</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">"Код памылкі MediaPlayer %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-bg/strings.xml b/leanback/res/values-bg/strings.xml
deleted file mode 100644
index f10878c..0000000
--- a/leanback/res/values-bg/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">"Контролите за мултимедия са скрити. Натиснете контролния пад, за да се покажат"</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">"Код на грешката на MediaPlayer %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-bn/strings.xml b/leanback/res/values-bn/strings.xml
deleted file mode 100644
index d0e08c4..0000000
--- a/leanback/res/values-bn/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">"মিডিয়ার নিয়ন্ত্রণগুলি লুকানো আছে, দেখার জন্য ডি-প্যাড টিপুন"</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">"MediaPlayer ত্রুটি কোড %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-bs/strings.xml b/leanback/res/values-bs/strings.xml
deleted file mode 100644
index 804d6ca..0000000
--- a/leanback/res/values-bs/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">"Meni za navigaciju"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Pretraživanje"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Pretraga"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Kažite nešto da pokrenete pretragu"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Pretraži <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Kažite nešto da pokrenete pretragu <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">"Reproduciraj"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Pauziraj"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Ubrzaj"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Ubrzaj %1$dX"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Premotaj"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Premotaj %1$dX"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Preskoči sljedeće"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Preskoči prethodno"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Više radnji"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Poništi pozitivnu ocjenu"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Odaberi pozitivnu ocjenu"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Poništi negativnu ocjenu"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Odaberi negativnu ocjenu"</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Ne ponavljaj"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Ponovi sve"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Ponovi jedno"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Uključi izmiješani redoslijed"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Isključi izmiješani redoslijed"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Uključi visoki kvalitet"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Isključi visoki kvalitet"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Uključi titlove"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Isključi titlove"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Uđi u način rada Slika u slici"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Kontrole za medije su prikazane"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Kontrole za medije su skrivene. Pritisnite d-pad da ih prikažete"</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Završiti"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Nastaviti"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"Kôd greške MediaPlayera %1$d dodatno %2$d"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"ZAPOČNITE"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Naprijed"</string>
-</resources>
diff --git a/leanback/res/values-ca/strings.xml b/leanback/res/values-ca/strings.xml
deleted file mode 100644
index a9dceaa..0000000
--- a/leanback/res/values-ca/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">"Menú de navegació"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Acció de cerca"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Cerca."</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Parla per fer una cerca."</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Cerca a <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>."</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Parla per cercar a <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">"Reprodueix"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Posa en pausa"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Avança ràpidament"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Avança ràpidament %1$dX"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Rebobina"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Rebobina %1$dX"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Passa al següent"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Passa a l\'anterior"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Més accions"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Anul·la \"M\'agrada\""</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Selecciona \"M\'agrada\""</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Anul·la \"No m\'agrada\""</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Selecciona \"M\'agrada\""</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"No en repeteixis cap"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Repeteix-ho tot"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Repeteix-ne un"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Activa la reproducció aleatòria"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Desactiva la reproducció aleatòria"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Activa l\'alta qualitat"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Desactiva l\'alta qualitat"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Activa els subtítols tancats"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Desactiva els subtítols tancats"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Entra al mode de pantalla en pantalla"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Es mostren els controls multimèdia"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"S\'han amagat els controls multimèdia; prem el teclat direccional per mostrar-los"</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Finalitza"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continua"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"Codi d\'error de MediaPlayer %1$d extra %2$d"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"COMENÇA"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Següent"</string>
-</resources>
diff --git a/leanback/res/values-cs/strings.xml b/leanback/res/values-cs/strings.xml
deleted file mode 100644
index aa521a3..0000000
--- a/leanback/res/values-cs/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">"Navigační nabídka"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Vyhledávání akce"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Vyhledávání"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Vyhledávejte hlasem"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Hledat <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Vyhledávejte v kategorii „<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>“ hlasem"</string>
-    <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$d×"</string>
-    <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$d×"</string>
-    <string name="lb_playback_controls_play" msgid="731953341987346903">"Přehrát"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Pozastavit"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Přetočit vpřed"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Přetočit vpřed %1$d×"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Přetočit zpět"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Přetočit zpět %1$d×"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Přeskočit na další"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Přeskočit na předchozí"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Další akce"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Zrušit výběr hodnocení palec nahoru"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Vybrat hodnocení palec nahoru"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Zrušit výběr hodnocení palec dolů"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Vybrat hodnocení palec dolů"</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Neopakovat"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Opakovat vše"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Opakovat jednu položku"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Zapnout náhodné přehrávání"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Vypnout náhodné přehrávání"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Zapnout vysokou kvalitu"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Vypnout vysokou kvalitu"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Zapnout titulky"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Vypnout titulky"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Přejít do režimu obraz v obraze"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Ovládací prvky médií jsou zobrazeny"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Ovládací prvky médií jsou skryty, zobrazíte je stisknutím křížového ovladače"</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Dokončit"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Pokračovat"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"Kód chyby přehrávače MediaPlayer %1$d, další %2$d"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"ZAČÍNÁME"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Další"</string>
-</resources>
diff --git a/leanback/res/values-da/strings.xml b/leanback/res/values-da/strings.xml
deleted file mode 100644
index 47bc465..0000000
--- a/leanback/res/values-da/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">"Navigationsmenu"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Søg handling"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Søg"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Tal for at søge"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Søg efter <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Sig noget for at søge i <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">"Afspil"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Sæt på pause"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Spol frem"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Spol frem %1$dX"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Spol tilbage"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Spol tilbage %1$dX"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Spring til næste"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Spring til forrige"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Flere handlinger"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Fravælg tommelfinger op"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Vælg tommelfinger op"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Fravælg tommelfinger ned"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Vælg tommelfinger ned"</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Gentag ingen"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Gentag alle"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Gentag en"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Aktivér bland"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Deaktiver bland"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Aktivér høj aktivitet"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Deaktiver høj kvalitet"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Aktivér undertekster"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Deaktiver undertekster"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Tilstand med integreret billede"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Knapperne til afspilning er synlige"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Knapperne til afspilning er skjult. Tryk på D-pad\'en for at se dem"</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Afslut"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Fortsæt"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"MediaPlayer-fejlkode %1$d ekstra %2$d"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"KOM GODT I GANG"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Næste"</string>
-</resources>
diff --git a/leanback/res/values-de/strings.xml b/leanback/res/values-de/strings.xml
deleted file mode 100644
index 8d909c2..0000000
--- a/leanback/res/values-de/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">"Navigationsmenü"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Suchvorgang"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Suchen"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Zum Suchen sprechen"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"In <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> suchen"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Sprechen, um in \"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>\" zu suchen"</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">"Wiedergabe"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Pausieren"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Vorspulen"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Vorspulen %1$dx"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Zurückspulen"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Zurückspulen %1$dx"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Nächsten Titel überspringen"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Vorherigen Titel überspringen"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Weitere Aktionen"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"\"Mag ich\" deaktivieren"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"\"Mag ich\" aktivieren"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"\"Mag ich nicht\" deaktivieren"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"\"Mag ich nicht\" aktivieren"</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Keinen Titel wiederholen"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Alle wiederholen"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Einen Titel wiederholen"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Zufallsmix aktivieren"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Zufallsmix deaktivieren"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Hohe Qualität aktivieren"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Hohe Qualität deaktivieren"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Untertitel aktivieren"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Untertitel deaktivieren"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Bild-im-Bild-Modus aktivieren"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Mediensteuerelemente eingeblendet"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Mediensteuerelemente ausgeblendet. Drücke das Steuerkreuz, um die Steuerelemente wieder einzublenden."</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Fertigstellen"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Weiter"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"MediaPlayer-Fehlercode %1$d extra %2$d"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"JETZT STARTEN"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Weiter"</string>
-</resources>
diff --git a/leanback/res/values-el/strings.xml b/leanback/res/values-el/strings.xml
deleted file mode 100644
index 795a501..0000000
--- a/leanback/res/values-el/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">"Κωδικός σφάλματος MediaPlayer %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-en-rAU/strings.xml b/leanback/res/values-en-rAU/strings.xml
deleted file mode 100644
index 03dedda..0000000
--- a/leanback/res/values-en-rAU/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">"Navigation menu"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Search Action"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Search"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Speak to search"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Search <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Speak to search <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">"Play"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Pause"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Fast-Forward"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Fast Forward %1$dX"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Rewind"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Rewind %1$dX"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Skip Next"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Skip Previous"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"More Actions"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Deselect Thumb Up"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Select Thumb Up"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Deselect Thumb Down"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Select Thumb Down"</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Repeat None"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Repeat All"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Repeat One"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Enable Shuffle"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Disable Shuffle"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Enable High Quality"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Disable High Quality"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Enable Closed Captioning"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Disable Closed Captioning"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Enter Picture In Picture Mode"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Media controls shown"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Media controls hidden, press d-pad to show"</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Finish"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continue"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"MediaPlayer error code %1$d extra %2$d"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"GET STARTED"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Next"</string>
-</resources>
diff --git a/leanback/res/values-en-rCA/strings.xml b/leanback/res/values-en-rCA/strings.xml
deleted file mode 100644
index 03dedda..0000000
--- a/leanback/res/values-en-rCA/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">"Navigation menu"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Search Action"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Search"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Speak to search"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Search <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Speak to search <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">"Play"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Pause"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Fast-Forward"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Fast Forward %1$dX"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Rewind"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Rewind %1$dX"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Skip Next"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Skip Previous"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"More Actions"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Deselect Thumb Up"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Select Thumb Up"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Deselect Thumb Down"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Select Thumb Down"</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Repeat None"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Repeat All"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Repeat One"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Enable Shuffle"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Disable Shuffle"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Enable High Quality"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Disable High Quality"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Enable Closed Captioning"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Disable Closed Captioning"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Enter Picture In Picture Mode"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Media controls shown"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Media controls hidden, press d-pad to show"</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Finish"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continue"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"MediaPlayer error code %1$d extra %2$d"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"GET STARTED"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Next"</string>
-</resources>
diff --git a/leanback/res/values-en-rGB/strings.xml b/leanback/res/values-en-rGB/strings.xml
deleted file mode 100644
index 03dedda..0000000
--- a/leanback/res/values-en-rGB/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">"Navigation menu"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Search Action"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Search"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Speak to search"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Search <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Speak to search <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">"Play"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Pause"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Fast-Forward"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Fast Forward %1$dX"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Rewind"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Rewind %1$dX"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Skip Next"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Skip Previous"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"More Actions"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Deselect Thumb Up"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Select Thumb Up"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Deselect Thumb Down"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Select Thumb Down"</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Repeat None"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Repeat All"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Repeat One"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Enable Shuffle"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Disable Shuffle"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Enable High Quality"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Disable High Quality"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Enable Closed Captioning"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Disable Closed Captioning"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Enter Picture In Picture Mode"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Media controls shown"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Media controls hidden, press d-pad to show"</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Finish"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continue"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"MediaPlayer error code %1$d extra %2$d"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"GET STARTED"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Next"</string>
-</resources>
diff --git a/leanback/res/values-en-rIN/strings.xml b/leanback/res/values-en-rIN/strings.xml
deleted file mode 100644
index 03dedda..0000000
--- a/leanback/res/values-en-rIN/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">"Navigation menu"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Search Action"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Search"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Speak to search"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Search <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Speak to search <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">"Play"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Pause"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Fast-Forward"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Fast Forward %1$dX"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Rewind"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Rewind %1$dX"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Skip Next"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Skip Previous"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"More Actions"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Deselect Thumb Up"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Select Thumb Up"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Deselect Thumb Down"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Select Thumb Down"</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Repeat None"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Repeat All"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Repeat One"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Enable Shuffle"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Disable Shuffle"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Enable High Quality"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Disable High Quality"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Enable Closed Captioning"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Disable Closed Captioning"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Enter Picture In Picture Mode"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Media controls shown"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Media controls hidden, press d-pad to show"</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Finish"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continue"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"MediaPlayer error code %1$d extra %2$d"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"GET STARTED"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Next"</string>
-</resources>
diff --git a/leanback/res/values-en-rXC/strings.xml b/leanback/res/values-en-rXC/strings.xml
deleted file mode 100644
index 92f9b9a..0000000
--- a/leanback/res/values-en-rXC/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">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‏‎‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‎‏‎‎‎‎‎‏‎‎‎‏‎‏‏‎‎‎‏‏‎‏‏‎‏‏‏‎‎‎‎‏‎Navigation menu‎‏‎‎‏‎"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‏‎‏‏‎‏‎‏‎‏‎‏‏‎‏‏‎‎‏‎‏‏‏‎‏‏‎‎‎‎‏‏‏‏‏‏‏‎‏‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‎Search Action‎‏‎‎‏‎"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‎‏‎‏‎‎‎‎‏‎‏‎‏‏‏‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‏‎‎‏‎‏‎‏‏‎‎‎‏‎‏‎‎‏‏‏‎‎‎Search‎‏‎‎‏‎"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‎‎‏‏‏‏‎‏‏‏‏‏‏‎‏‏‏‏‎‎‏‏‏‎‏‎‎‏‎‎‏‎‎‏‏‏‏‏‎‎‏‎‏‏‎‎‏‎‎‎‎‎‎‏‎‎‎‎Speak to search‎‏‎‎‏‎"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‎‏‎‎‏‎‏‎‎‏‎‏‎‎‎‎‏‏‏‏‎‎‏‏‏‎‏‏‏‏‏‎‏‎‎‏‎‎‎‏‏‏‎‎‎‏‎‎‏‏‏‎‏‎‎‏‏‎Search ‎‏‎‎‏‏‎<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‏‎‏‎‎‏‎‏‏‎‎‏‎‎‎‏‏‏‎‎‏‎‎‎‎‎‏‏‏‏‎‏‎‎‏‎‏‎‏‏‎‎‎‏‎‏‎‎‎‏‏‎‎‎‏‎‎Speak to search ‎‏‎‎‏‏‎<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">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‎‎‎‏‎‏‎‎‎‎‏‏‎‏‎‏‏‏‎‏‎‏‏‏‏‏‎‏‏‏‏‎‏‎‏‎‏‎‎‎‎‏‏‎‏‏‎‎‏‏‏‎‏‎‏‏‏‎Play‎‏‎‎‏‎"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‏‏‎‎‏‎‏‏‎‎‏‏‎‎‎‏‎‏‎‏‎‎‎‎‏‏‎‏‏‏‏‎‏‎‎‏‏‎‎‏‏‎‏‏‎‎‎‎‎‏‎‏‏‏‎‎Pause‎‏‎‎‏‎"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‎‏‏‏‎‏‎‎‏‎‏‎‏‎‏‎‏‎‎‎‏‏‎‎‎‎‎‏‎‎‏‎‏‏‏‎‏‎‏‏‏‏‏‎‏‎‏‏‏‎‏‎‎‎Fast Forward‎‏‎‎‏‎"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‏‎‏‏‎‎‎‏‎‏‏‏‎‎‏‎‏‏‎‏‏‎‏‎‏‏‏‏‎‎‏‎‏‏‎‎‎‏‎‏‎‎‏‏‎‏‎‎‏‎‎‎‏‏‏‎‎Fast Forward %1$dX‎‏‎‎‏‎"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‏‏‏‎‏‎‎‎‏‎‎‏‎‏‏‏‎‏‎‎‎‏‎‎‎‎‎‎‎‏‎‏‎‎‎‎‎‎‏‎‏‏‎‎‏‏‏‎‏‏‎‏‏‏‎‎‎Rewind‎‏‎‎‏‎"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‎‏‏‎‎‎‏‎‎‏‎‏‎‏‏‏‏‏‏‎‏‏‏‎‏‏‏‎‎‏‏‎‏‏‎‎‎‏‏‎‎‎‎‏‎‎‏‎‎‎‎‎‏‎‏‏‎‎Rewind %1$dX‎‏‎‎‏‎"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‏‏‏‎‎‏‎‎‎‎‎‏‎‎‎‏‏‎‏‎‏‏‎‏‏‎‎‎‎‏‎‎‏‎‏‏‏‏‎‎‎‏‎‏‎‎‏‎‎‏‎‏‏‏‎‎‎Skip Next‎‏‎‎‏‎"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‎‏‎‎‏‎‏‎‎‏‏‏‎‏‎‏‏‏‏‏‎‎‎‎‎‏‏‎‏‎‏‎‏‎‏‏‎‏‎‏‏‎‏‏‏‎‏‏‏‏‏‎‏‏‎‎‎Skip Previous‎‏‎‎‏‎"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‎‏‎‏‏‎‎‎‏‎‎‎‏‏‏‎‏‏‏‏‏‎‎‏‎‏‎‏‏‎‏‏‎‏‏‏‏‎‏‎‏‎‎‎‎‎‎‏‎‎‎‎‎‏‏‏‎More Actions‎‏‎‎‏‎"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‎‏‎‎‎‎‎‏‎‏‏‎‏‏‎‏‎‏‏‎‏‎‎‏‏‎‎‎‎‎‎‏‎‎‏‏‏‏‎‏‏‎‏‎‏‎‏‏‏‎‎‏‎‎‏‎Deselect Thumb Up‎‏‎‎‏‎"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‏‏‏‎‎‏‎‎‏‏‏‎‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‎‏‏‎‎‎‏‏‎‏‎‎‏‏‏‎‏‎‎‏‏‏‎‎‏‎‎‏‎‎Select Thumb Up‎‏‎‎‏‎"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‎‏‏‎‎‎‏‎‎‎‎‎‎‏‎‏‎‎‎‏‎‎‎‏‏‎‎‎‎‎‎‏‎‎‏‏‎‎‎‎‏‎‏‎‏‏‎‏‏‏‏‎‏‎Deselect Thumb Down‎‏‎‎‏‎"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‎‏‎‏‏‎‏‏‏‎‎‎‏‏‏‎‏‏‏‎‎‎‎‏‎‎‎‎‏‎‎‏‏‏‎‎‎‎‏‏‏‎‏‏‎‏‎Select Thumb Down‎‏‎‎‏‎"</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‏‏‎‎‏‏‎‏‏‎‏‏‎‎‎‏‏‏‏‏‎‏‎‎‎‏‏‏‏‏‏‏‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‎‎‏‏‎‎‎Repeat None‎‏‎‎‏‎"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‏‎‎‏‏‏‎‎‎‎‎‏‎‏‏‎‏‎‏‏‎‎‎‏‏‎‏‏‏‏‎‏‏‎‎‎‎‎‎‏‏‎‏‎‏‎‎‎‎‏‏‎‎‎‎Repeat All‎‏‎‎‏‎"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‏‏‎‎‏‎‏‏‏‎‏‏‎‎‎‏‎‎‎‎‏‏‎‎‏‏‏‎‏‏‏‏‏‎‏‏‎‏‏‎‎‏‎‎‎‏‏‎‎‎‏‏‎‎‎‏‏‎Repeat One‎‏‎‎‏‎"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‎‏‎‎‎‎‏‏‏‎‎‎‏‎‎‏‏‎‏‎‏‏‎‎‎‏‏‏‎‏‏‏‎‎‏‎‏‎‏‏‏‎‏‎‏‏‏‎‎‎‎‏‎‎‎‏‎Enable Shuffle‎‏‎‎‏‎"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‎‏‎‎‎‏‎‏‏‎‎‏‎‏‎‎‎‎‏‏‎‏‎‏‎‎‏‎‎‏‎‏‎‎‎‏‏‏‏‏‎‎‏‎‏‏‏‎‏‏‎‏‎‎Disable Shuffle‎‏‎‎‏‎"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‎‏‏‎‎‏‏‏‏‎‎‏‎‎‎‎‎‎‎‎‏‎‏‎‎‎‏‎‏‏‎‎‎‏‏‏‏‏‏‎‎‎‏‏‏‎‎‎‎‎‏‎‏‎‏‏‎‎Enable High Quality‎‏‎‎‏‎"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‏‏‏‏‎‎‎‎‏‏‎‏‏‏‎‏‏‎‎‎‏‎‎‎‏‏‎‎‎‏‎‎‏‏‎‎‏‎‏‏‎‎‏‏‎‏‏‎‎‏‎‏‎‎Disable High Quality‎‏‎‎‏‎"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‏‎‏‏‎‏‏‏‏‏‎‏‏‏‏‎‏‎‏‎‏‏‏‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‎‎‏‎‎‏‎‎‏‏‎‏‎‎‎‏‎‎Enable Closed Captioning‎‏‎‎‏‎"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‎‏‏‏‏‎‎‎‎‏‎‏‎‎‎‏‎‎‎‎‏‎‏‏‎‎‎‎‎‏‏‎‏‏‏‏‎‎‎‎‏‏‏‎‏‏‏‏‎‎‎‎‎‎‎Disable Closed Captioning‎‏‎‎‏‎"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‎‎‎‏‏‎‎‎‎‎‏‏‎‎‎‎‎‎‎‏‏‏‎‎‏‎‏‎‏‎‎‎‏‎‎‎‏‏‏‎‏‎‎‏‎‎‎‎‏‎‎‏‎‎‎‏‎‎Enter Picture In Picture Mode‎‏‎‎‏‎"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‎‏‎‎‎‎‏‏‎‎‏‏‏‎‏‎‏‎‏‎‏‏‎‎‎‎‏‎‎‏‎‎‎‏‎‎‎‎‏‎‏‎‎‎‎‎‎‎‎‏‎‎‎‏‏‏‏‎/‎‏‎‎‏‎"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‎‎‏‎‎‎‏‏‏‏‏‏‏‎‎‏‏‎‏‎‏‎‎‎‏‎‎‎‎‎‎‏‏‎‏‏‎‏‎‎‏‏‎‎‎‎‎‏‏‎‎‎‏‏‎‎Media controls shown‎‏‎‎‏‎"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‏‎‎‏‏‎‎‎‎‎‏‏‎‏‎‎‏‏‎‏‎‎‎‏‎‎‎‏‏‎‏‏‎‏‎‏‎‎‎‏‏‎‏‏‎‏‎‎‏‏‎‎Media controls hidden, press d-pad to show‎‏‎‎‏‎"</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‏‏‎‏‏‏‎‎‎‏‏‎‏‎‎‏‎‎‏‎‏‎‏‏‏‎‏‏‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‏‎‏‎‎‎‎‎‏‎‏‎Finish‎‏‎‎‏‎"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‎‏‎‏‏‎‏‏‏‎‎‏‏‏‏‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‎‎‎‏‏‏‎‏‏‎‏‎‎‏‏‎‏‎‎Continue‎‏‎‎‏‎"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‏‎‏‎‏‎‎‎‎‏‎‎‏‎‏‏‏‏‏‏‎‎‎‎‎‏‏‏‏‎‎‏‏‎‎‎‏‏‎‏‎‎‎‎‎‎‎‏‏‎‏‏‎‏‎‎‎MediaPlayer error code %1$d extra %2$d‎‏‎‎‏‎"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‎‏‏‏‎‎‎‎‎‎‎‎‎‏‎‎‏‎‎‏‏‏‎‎‎‏‎‎‎‎‏‏‎‏‏‏‏‏‎‎‎‏‎‎‏‎‎‎‏‎‎‎‏‏‎GET STARTED‎‏‎‎‏‎"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‏‏‏‎‏‏‎‎‏‏‏‎‎‎‎‏‏‏‎‏‎‏‎‎‏‎‏‏‏‎‏‎‏‎‎‏‎‎Next‎‏‎‎‏‎"</string>
-</resources>
diff --git a/leanback/res/values-es-rUS/strings.xml b/leanback/res/values-es-rUS/strings.xml
deleted file mode 100644
index cf84f62..0000000
--- a/leanback/res/values-es-rUS/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">"Menú de navegación"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Acción de búsqueda"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Búsqueda"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Habla para buscar"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Buscar <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Habla para buscar en <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">"Reproducir"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Pausar"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Avanzar"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Avanzar rápidamente %1$dX"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Retroceder"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Rebobinar %1$dX"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Ir al siguiente"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Ir al anterior"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Más acciones"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Desmarcar \"Me gusta\""</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Marcar \"Me gusta\""</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Desmarcar \"No me gusta\""</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Marcar \"No me gusta\""</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"No repetir"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Repetir todo"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Repetir uno"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Habilitar reproducción aleatoria"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Inhabilitar reproducción aleatoria"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Habilitar calidad alta"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Inhabilitar calidad alta"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Habilitar subtítulos"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Inhabilitar subtítulos"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Activar el modo Imagen en imagen"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Se muestran los controles de medios"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Los controles de medios están ocultos; presiona el control direccional para mostrarlos"</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Finalizar"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continuar"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"Código de error de MediaPlayer %1$d extra %2$d"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"COMENZAR"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Siguiente"</string>
-</resources>
diff --git a/leanback/res/values-es/strings.xml b/leanback/res/values-es/strings.xml
deleted file mode 100644
index bae575f..0000000
--- a/leanback/res/values-es/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">"Menú de navegación"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Buscar..."</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Buscar"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Habla para buscar"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Buscar <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Habla para buscar en <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">"Reproducir"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Pausar"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Avance rápido"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Avance rápido %1$dX"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Rebobinar"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Rebobinar %1$dX"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Saltar siguiente"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Saltar anterior"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Más acciones"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"No seleccionar pulgar hacia arriba"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Seleccionar pulgar hacia arriba"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"No seleccionar pulgar hacia abajo"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Seleccionar pulgar hacia abajo"</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"No repetir"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Repetir todo"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Repetir uno"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Habilitar reproducción aleatoria"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Inhabilitar reproducción aleatoria"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Habilitar alta calidad"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Inhabilitar alta calidad"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Habilitar subtítulos"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Inhabilitar subtítulos"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Activar modo Imagen en imagen"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Controles multimedia mostrados"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Controles multimedia ocultos (pulsa la cruceta para mostrarlos)"</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Finalizar"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continuar"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"Código de error de MediaPlayer %1$d extra %2$d"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"EMPEZAR"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Siguiente"</string>
-</resources>
diff --git a/leanback/res/values-et/strings.xml b/leanback/res/values-et/strings.xml
deleted file mode 100644
index 34a4f0c..0000000
--- a/leanback/res/values-et/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">"Navigeerimismenüü"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Otsimistoiming"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Otsing"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Öelge otsimiseks"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Otsige teenusest <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Häälotsing: <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">"Esita"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Peata"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Keri edasi"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Edasikerimine %1$dX"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Keri tagasi"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Tagasikerimine %1$dX"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Liigu järgmise üksuse juurde"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Liigu eelmise üksuse juurde"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Veel toiminguid"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Tühista hinnang Meeldib"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Vali hinnang Meeldib"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Tühista hinnang Ei meeldi"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Vali hinnang Ei meeldi"</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Ära korda midagi"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Korda kõike"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Korda ühte"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Luba juhuslikus järjekorras esitamine"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Keela juhuslikus järjekorras esitamine"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Luba kõrgkvaliteetne taasesitus"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Keela kõrgkvaliteetne taasesitus"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Luba subtiitrid"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Keela subtiitrid"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Sisene režiimi Pilt pildis"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Meedia juhtnupud on kuvatud"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Meedia juhtnupud on peidetud, kuvamiseks vajutage DPAD-i"</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Lõpeta"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Jätka"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"MediaPlayeri veakood %1$d, lisa %2$d"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"ALUSTAGE"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Järgmine"</string>
-</resources>
diff --git a/leanback/res/values-eu/strings.xml b/leanback/res/values-eu/strings.xml
deleted file mode 100644
index e8f702e..0000000
--- a/leanback/res/values-eu/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">"Nabigazio-menua"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Bilaketa"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Bilatu"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Esan bilatu nahi duzuna"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Bilatu <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Esan bilatu nahi duzuna, bilaketa hemen egiteko: <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">"Erreproduzitu"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Pausatu"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Aurreratu"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Aurreratu %1$dX"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Atzeratu"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Atzeratu %1$dX"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Saltatu hurrengora"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Saltatu aurrekora"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Ekintza gehiago"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Desautatu \"erpurua gora\""</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Hautatu \"erpurua gora\""</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Desautatu \"erpurua behera\""</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Hautatu \"erpurua behera\""</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Ez errepikatu"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Errepikatu guztiak"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Errepikatu bat"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Gaitu ausazko erreprodukzioa"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Desgaitu ausazko erreprodukzioa"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Gaitu kalitate handiko erreprodukzioa"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Desgaitu kalitate handiko erreprodukzioa"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Gaitu azpitituluak"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Desgaitu azpitituluak"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Aktibatu \"Pantaila txiki gainjarri\" modua"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Multimedia kontrolatzeko aukerak ikusgai"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Ezkutatuta daude multimedia kontrolatzeko aukerak. Erakusteko, sakatu nabigazio-gurutzea."</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Amaitu"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Jarraitu"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"MediaPlayer errore-kodea: %1$d (%2$d gehigarria)"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"HASI ERABILTZEN"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Hurrengoa"</string>
-</resources>
diff --git a/leanback/res/values-fa/strings.xml b/leanback/res/values-fa/strings.xml
deleted file mode 100644
index 8f47a57..0000000
--- a/leanback/res/values-fa/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">"‏کد خطای MediaPlayer‏ %1$d extra %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-fi/strings.xml b/leanback/res/values-fi/strings.xml
deleted file mode 100644
index 863fcd5..0000000
--- a/leanback/res/values-fi/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">"Navigointivalikko"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Hakutoiminto"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Haku"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Tee haku puhumalla"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Haku: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Hae <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> puhehaulla"</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">"Toista"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Keskeytä"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Kelaa eteenpäin"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Kelaa eteenpäin %1$dX"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Kelaa taakse"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Kelaa taaksepäin %1$dX"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Siirry seuraavaan"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Siirry edelliseen"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Lisää toimintoja"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Poista Tykkään-valinta"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Valitse Tykkään"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Poista En tykkää -valinta"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Valitse En tykkää"</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Ei uudelleentoistoa"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Toista kaikki uudelleen"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Toista yksi uudelleen"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Ota satunnaistoisto käyttöön"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Poista satunnaistoisto käytöstä"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Ota korkea laatu käyttöön"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Poista korkea laatu käytöstä"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Ota tekstitys käyttöön"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Poista tekstitys käytöstä"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Vaihda kuva kuvassa ‑tilaan"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Mediasäätimet näkyvissä"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Mediasäätimet piilotettu, näytä painamalla ohjaimen nuolia."</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Valmis"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Jatka"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"MediaPlayerin virhekoodi %1$d ylimääräinen %2$d"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"ALOITA"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Seuraava"</string>
-</resources>
diff --git a/leanback/res/values-fr-rCA/strings.xml b/leanback/res/values-fr-rCA/strings.xml
deleted file mode 100644
index d8ec857..0000000
--- a/leanback/res/values-fr-rCA/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">"Menu de navigation"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Action de recherche"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Rechercher"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Énoncez votre recherche"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Rechercher dans <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Énoncez votre recherche dans <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">"Lecture"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Pause"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Avance rapide"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Avance rapide à %1$dX"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Reculer"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Retour rapide à %1$dX"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Passer à l\'élément suivant"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Passer à l\'élément précédent"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Autres actions"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Désélectionner la mention « J\'aime »"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Sélectionner la mention « J\'aime »"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Désélectionner la mention « Je n\'aime pas »"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Sélectionner la mention « Je n\'aime pas »"</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Aucune répétition"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Tout lire en boucle"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Répéter un élément"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Activer la lecture aléatoire"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Désactiver la lecture aléatoire"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Activer la lecture haute qualité"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Désactiver la lecture haute qualité"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Activer le sous-titrage"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Désactiver le sous-titrage"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Activer le mode Incrustation d\'image"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Les commandes multimédias sont affichées"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Les commandes multimédias sont masquées, appuyez sur le pavé directionnel pour les afficher."</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Terminer"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continuer"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"Code d\'erreur MediaPlayer %1$d extra %2$d"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"COMMENCER"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Suivant"</string>
-</resources>
diff --git a/leanback/res/values-fr/strings.xml b/leanback/res/values-fr/strings.xml
deleted file mode 100644
index 32f78d3..0000000
--- a/leanback/res/values-fr/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">"Menu de navigation"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Commande de recherche"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Rechercher"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Énoncer la recherche"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Rechercher \"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>\""</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Énoncez votre recherche sur \"<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">"Lecture"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Interrompre"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Avance rapide"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Avance rapide de %1$dX"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Retour arrière"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Retour arrière de %1$dX"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Ignorer l\'élément suivant"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Ignorer l\'élément précédent"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Autres actions"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Annuler +1"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Sélectionner +1"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Annuler -1"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Sélectionner -1"</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Ne rien lire en boucle"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Tout lire en boucle"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Lire en boucle un élément"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Désactiver la lecture en mode aléatoire"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Désactiver la lecture en mode aléatoire"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Activer la haute qualité"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Désactiver la haute qualité"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Activer les sous-titres"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Désactiver les sous-titres"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Activer le mode Picture-in-picture"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Les commandes multimédias sont affichées"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Les commandes multimédias sont masquées. Appuyez sur le pavé directionnel pour les afficher"</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Terminer"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continuer"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"Code d\'erreur MediaPlayer %1$d extra %2$d"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"COMMENCER"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Suivant"</string>
-</resources>
diff --git a/leanback/res/values-gl/strings.xml b/leanback/res/values-gl/strings.xml
deleted file mode 100644
index af84c09..0000000
--- a/leanback/res/values-gl/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">"Menú de navegación"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Acción de busca"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Buscar"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Fala para efectuar a busca"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Busca <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Fala para buscar <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">"Reproducir"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Pausar"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Avance rápido"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Avance rápido %1$dX"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Rebobinar"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Rebobinado %1$dX"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Saltar seguinte"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Saltar anterior"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Máis accións"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Anular \"Gústame\""</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Seleccionar polgar cara arriba"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Anular \"Non me gusta\""</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Seleccionar polgar cara abaixo"</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Non repetir"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Repetir todo"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Repetir un"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Activar reprodución aleatoria"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Desactivar reprodución aleatoria"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Activar alta calidade"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Desactivar alta calidade"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Activar subtítulos"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Desactivar subtítulos"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Activar o modo Pantalla superposta"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Móstranse os controis de recursos multimedia"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Os controis de recursos multimedia están ocultos. Preme d-pad para mostralos"</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Finalizar"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continuar"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"Código de erro de MediaPlayer %1$d %2$d de máis"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"INTRODUCIÓN"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Seguinte"</string>
-</resources>
diff --git a/leanback/res/values-gu/strings.xml b/leanback/res/values-gu/strings.xml
deleted file mode 100644
index c5fb2d0..0000000
--- a/leanback/res/values-gu/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-પૅડ દબાવો"</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">"MediaPlayer ભૂલ કોડ %1$d extra %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-hi/strings.xml b/leanback/res/values-hi/strings.xml
deleted file mode 100644
index 00ef8ab..0000000
--- a/leanback/res/values-hi/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">"मीडिया नियंत्रण छिपे हुए हैं, दिखाने के लिए डी-पैड दबाएं"</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-hr/strings.xml b/leanback/res/values-hr/strings.xml
deleted file mode 100644
index 02e5386..0000000
--- a/leanback/res/values-hr/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">"Navigacijski izbornik"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Radnja pretraživanja"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Pretražite"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Izgovorite upit za pretraživanje"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Tražite <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Izgovorite upit da pretražite uslugu <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">"Reproduciraj"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Pauziraj"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Brzo naprijed"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Brzo unaprijed %1$dX"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Unatrag"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Unatrag %1$dX"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Preskoči na sljedeće"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Preskoči na prethodno"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Više radnji"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Poništi odabir palca gore"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Odaberi palac gore"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Poništi odabir palca dolje"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Odaberi palac dolje"</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Bez ponavljanja"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Ponovi sve"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Ponovi jedno"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Omogući nasumičnu reprodukciju"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Onemogući nasumičnu reprodukciju"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Omogući visoku kvalitetu"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Onemogući visoku kvalitetu"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Omogući titlove"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Onemogući titlove"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Unos slike u načinu slike"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Medijske kontrole prikazane"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Medijske kontrole skrivene su, pritisnite D-pad za prikaz"</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Završi"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Nastavi"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"Kôd pogreške MediaPlayera: %1$d, dodatno %2$d"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"POČETAK"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Dalje"</string>
-</resources>
diff --git a/leanback/res/values-hu/strings.xml b/leanback/res/values-hu/strings.xml
deleted file mode 100644
index 96ef017..0000000
--- a/leanback/res/values-hu/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">"Navigációs menü"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Keresési művelet"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Keresés"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Beszéljen a keresés indításához"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Keresés itt: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Mondj valamit a kereséshez: <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">"Lejátszás"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Szünet"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Gyors előretekerés"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Előretekerés %1$dX"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Visszatekerés"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Visszatekerés %1$dX"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Ugrás a következőre"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Ugrás az előzőre"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"További műveletek"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"„Tetszik” értékelés visszavonása"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"„Tetszik” értékelés kiválasztása"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"„Nem tetszik” értékelés visszavonása"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"„Nem tetszik” értékelés kiválasztása"</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Nincs ismétlés"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Összes ismétlése"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Egy ismétlése"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Véletlenszerű lejátszás engedélyezése"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Véletlenszerű lejátszás letiltása"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Jó minőségű lejátszás engedélyezése"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Jó minőségű lejátszás letiltása"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Feliratok engedélyezése"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Feliratok letiltása"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Kép a képben mód indítása"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Médiavezérlők megjelenítve"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"A médiavezérlők el vannak rejtve. Megjelenítésükhöz nyomja le a d-padet."</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Befejezés"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Folytatás"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"MediaPlayer-hibakód: %1$d extra %2$d"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"KEZDŐ LÉPÉSEK"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Következő"</string>
-</resources>
diff --git a/leanback/res/values-hy/strings.xml b/leanback/res/values-hy/strings.xml
deleted file mode 100644
index e71bc52..0000000
--- a/leanback/res/values-hy/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/res/values-in/strings.xml b/leanback/res/values-in/strings.xml
deleted file mode 100644
index da32e15..0000000
--- a/leanback/res/values-in/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">"Menu navigasi"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Tindakan Penelusuran"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Telusuri"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Ucapkan untuk menelusuri"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Telusuri <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Ucapkan untuk menelusuri <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">"Putar"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Jeda"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Maju Cepat"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Maju %1$dX"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Putar Ulang"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Mundur %1$dX"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Lewati ke Berikutnya"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Lewati ke Sebelumnya"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Tindakan Lainnya"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Batal Pilih Yang Disukai"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Pilih Yang Disukai"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Batal Pilih Yang Tidak Disukai"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Pilih Yang Tidak Disukai"</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Jangan Ulangi"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Ulangi Semua"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Ulangi Satu"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Aktifkan Acak"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Nonaktifkan Acak"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Aktifkan Kualitas Tinggi"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Nonaktifkan Kualitas Tinggi"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Aktifkan Pembuatan Teks"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Nonaktifkan Pembuatan Teks"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Masuk Mode Picture In Picture"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Kontrol media ditampilkan"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Kontrol media disembunyikan, tekan d-pad untuk menampilkannya"</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Selesai"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Lanjutkan"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"Kode error MediaPlayer %1$d ekstra %2$d"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"MULAI"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Berikutnya"</string>
-</resources>
diff --git a/leanback/res/values-is/strings.xml b/leanback/res/values-is/strings.xml
deleted file mode 100644
index afd1709..0000000
--- a/leanback/res/values-is/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">"Yfirlitsvalmynd"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Leitaraðgerð"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Leita"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Talaðu til að leita"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Leita í <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Talaðu til að leita í <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">"Spila"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Hlé"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Spóla áfram"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Spóla áfram %1$dX"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Spóla til baka"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Spóla til baka %1$dX"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Fara í næsta"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Fara í fyrra"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Fleiri aðgerðir"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Hætta við þumal upp"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Gefa þumal upp"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Hætta við þumal niður"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Gefa þumal niður"</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Endurtaka ekkert"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Endurtaka allt"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Endurtaka eitt"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Kveikja á stokkun"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Slökkva á stokkun"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Kveikja á miklum gæðum"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Slökkva á miklum gæðum"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Kveikja á skjátextum"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Slökkva á skjátextum"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Skoða mynd í myndsniði"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Spilunarstýringar sýndar"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Spilunarstýringar faldar, ýttu á stefnuhnappa til að sýna þær"</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Ljúka"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Halda áfram"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"Villukóði MediaPlayer %1$d aukalegt %2$d"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"HEFJAST HANDA"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Áfram"</string>
-</resources>
diff --git a/leanback/res/values-it/strings.xml b/leanback/res/values-it/strings.xml
deleted file mode 100644
index 69fe31e..0000000
--- a/leanback/res/values-it/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">"Menu di navigazione"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Azione di ricerca"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Ricerca"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Parla per cercare"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Cerca in <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Parla per cercare in <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">"Riproduci"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Metti in pausa"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Avanza velocemente"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Avanti veloce: %1$dX"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Riavvolgi"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Indietro: %1$dX"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Salta successivo"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Salta precedente"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Altre azioni"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Deseleziona Mi piace"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Seleziona Mi piace"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Deseleziona pollice abbassato"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Seleziona pollice abbassato"</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Non ripetere nessuno"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Ripeti tutti"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Ripeti uno"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Attiva riproduzione casuale"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Disattiva riproduzione casuale"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Attiva alta qualità"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Disattiva alta qualità"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Attiva sottotitoli"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Disattiva sottotitoli"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Attiva modalità Picture in picture"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Controlli multimediali visualizzati"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Controlli multimediali nascosti, premi il d-pad per visualizzarli"</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Fine"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continua"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"Codice di errore MediaPlayer %1$d extra %2$d"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"INIZIA"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Avanti"</string>
-</resources>
diff --git a/leanback/res/values-iw/strings.xml b/leanback/res/values-iw/strings.xml
deleted file mode 100644
index d3a7ec4..0000000
--- a/leanback/res/values-iw/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‏ של MediaPlayer ועוד %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-ja/strings.xml b/leanback/res/values-ja/strings.xml
deleted file mode 100644
index c7fe665..0000000
--- a/leanback/res/values-ja/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">"1曲を繰り返し"</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">"MediaPlayer エラーコード: %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-ka/strings.xml b/leanback/res/values-ka/strings.xml
deleted file mode 100644
index 7ca9ff8..0000000
--- a/leanback/res/values-ka/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">"MediaPlayer-ის შეცდომის კოდი: %1$d extra %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-kk/strings.xml b/leanback/res/values-kk/strings.xml
deleted file mode 100644
index 22c67b2..0000000
--- a/leanback/res/values-kk/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-тақтасын басыңыз"</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">"MediaPlayer қате коды %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-km/strings.xml b/leanback/res/values-km/strings.xml
deleted file mode 100644
index 2712577..0000000
--- a/leanback/res/values-km/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">"លេខកូដបញ្ហា MediaPlayer %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-kn/strings.xml b/leanback/res/values-kn/strings.xml
deleted file mode 100644
index f84a64b..0000000
--- a/leanback/res/values-kn/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/res/values-ko/strings.xml b/leanback/res/values-ko/strings.xml
deleted file mode 100644
index 40ddd1b..0000000
--- a/leanback/res/values-ko/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$d배속"</string>
-    <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$d배속"</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$d배속 빨리 감기"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"되감기"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"%1$d배속 되감기"</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">"PIP 모드 시작"</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">"MediaPlayer 오류 코드 %1$d extra %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-ky/strings.xml b/leanback/res/values-ky/strings.xml
deleted file mode 100644
index e368e06..0000000
--- a/leanback/res/values-ky/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">"MediaPlayer\'деги катанын коду: 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-lo/strings.xml b/leanback/res/values-lo/strings.xml
deleted file mode 100644
index 4e11fcf..0000000
--- a/leanback/res/values-lo/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">"ເຊື່ອງຕົວຄວບຄຸມມີເດຍແລ້ວ, ກົດປຸ່ມທິດທາງເພື່ອສະແດງ"</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">"ລະຫັດ MediaPlayer ຜິດພາດ %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-lt/strings.xml b/leanback/res/values-lt/strings.xml
deleted file mode 100644
index d3ee2c6..0000000
--- a/leanback/res/values-lt/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">"Naršymo meniu"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Paieškos veiksmas"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Paieška"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Pasakykite, kad ieškotumėte"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Ieškoti „<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>“"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Kalbėkite, kad ieškotumėte „<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>“"</string>
-    <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$d k."</string>
-    <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$d k."</string>
-    <string name="lb_playback_controls_play" msgid="731953341987346903">"Leisti"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Pristabdyti"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Sukti pirmyn"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Sukti pirmyn %1$d k. greičiau"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Sukti atgal"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Sukti atgal %1$d k. greičiau"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Praleisti kitą"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Praleisti ankstesnį"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Daugiau veiksmų"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Panaikinti parinkties „Patinka“ pasirinkimą"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Pasirinkti parinktį „Patinka“"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Panaikinti parinkties „Nepatinka“ pasirinkimą"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Pasirinkti parinktį „Nepatinka“"</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Nekartoti nieko"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Kartoti viską"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Kartoti vieną"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Įgalinti maišymą"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Išjungti maišymą"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Įgalinti aukštą kokybę"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Išjungti aukštą kokybę"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Įgalinti subtitrus"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Išjungti subtitrus"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Įjungti vaizdo vaizde režimą"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Medijos valdikliai rodomi"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Medijos valdikliai paslėpti. Paspauskite krypčių valdiklius, kad rodytumėte"</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Baigti"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Tęsti"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"%1$d ir %2$d „MediaPlayer“ klaidos kodas"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"PRADĖTI"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Kitas"</string>
-</resources>
diff --git a/leanback/res/values-lv/strings.xml b/leanback/res/values-lv/strings.xml
deleted file mode 100644
index a09411a..0000000
--- a/leanback/res/values-lv/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">"Navigācijas izvēlne"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Meklēšanas darbība"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Meklēt"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Runāt, lai meklētu"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Meklējiet <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Runājiet, lai meklētu: <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">"Atskaņot"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Pauzēt"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Pārtīt uz priekšu"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Pārtīt uz priekšu %1$dX"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Attīt atpakaļ"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Attīt atpakaļ %1$dX"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Izlaist nākamo"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Izlaist iepriekšējo"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Citas darbības"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Atcelt “Patīk” atlasi"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Atlasīt “Patīk”"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Atcelt “Nepatīk” atlasi"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Atlasīt “Nepatīk”"</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Neatkārtot nevienu"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Atkārtot visu"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Atkārtot vienu"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Iespējot atskaņošanu jauktā secībā"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Atspējot atskaņošanu jauktā secībā"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Iespējot augstas kvalitātes vienumu atskaņošanu"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Atspējot augstas kvalitātes vienumu atskaņošanu"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Iespējot slēgtos parakstus"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Atspējot slēgtos parakstus"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Aktivizēt režīmu Attēls attēlā"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Multivides vadīklas ir redzamas."</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Multivides vadīklas ir paslēptas. Nospiediet virzienu tastatūru, lai tās tiktu parādītas."</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Pabeigt"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Turpināt"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"MediaPlayer kļūdas kods: %1$d extra %2$d"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"SĀKT DARBU"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Nākamā"</string>
-</resources>
diff --git a/leanback/res/values-mk/strings.xml b/leanback/res/values-mk/strings.xml
deleted file mode 100644
index 8d6b89e..0000000
--- a/leanback/res/values-mk/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">"Контролите за аудио-визуелните медиуми се скриени, притиснете на подлогата за насока за да ги прикажете"</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">"Код за грешка на MediaPlayer %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-ml/strings.xml b/leanback/res/values-ml/strings.xml
deleted file mode 100644
index 2c18a2c..0000000
--- a/leanback/res/values-ml/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">"മീഡിയ നിയന്ത്രണങ്ങൾ ‌മറച്ചിരിക്കുന്നു, കാണിക്കുന്നതിന് ഡി-‌പാഡ് അമർത്തുക"</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-mn/strings.xml b/leanback/res/values-mn/strings.xml
deleted file mode 100644
index 7919146..0000000
--- a/leanback/res/values-mn/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">"MediaPlayer-н алдааны код %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-mr/strings.xml b/leanback/res/values-mr/strings.xml
deleted file mode 100644
index 1fcb920..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/res/values-ms/strings.xml b/leanback/res/values-ms/strings.xml
deleted file mode 100644
index b5437d8..0000000
--- a/leanback/res/values-ms/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">"Menu navigasi"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Tindakan Carian"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Carian"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Tutur untuk membuat carian"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Cari <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Sebut untuk mencari <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">"Main"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Jeda"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Mara Laju"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Lajukan %1$dX"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Gulung semula"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Gulung semula %1$dX"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Langkau Seterusnya"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Langkau Sebelumnya"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Lagi Tindakan"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Nyahpilih Bagus"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Pilih Bagus"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Nyahpilih Tidak Bagus"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Pilih Tidak Bagus"</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Jangan Ulang"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Ulang Semua"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Ulang Satu"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Dayakan Rombak"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Lumpuhkan Rombak"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Dayakan Kualiti Tinggi"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Lumpuhkan Kualiti Tinggi"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Dayakan Kapsyen Tertutup"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Lumpuhkan Kapsyen Tertutup"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Masukkan Gambar Dalam Mod Gambar"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Kawalan media ditunjukkan"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Kawalan media disembunyikan, tekan d-pad untuk menunjukkan"</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Selesai"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Teruskan"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"Kod ralat MediaPlayer %1$d tambahan %2$d"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"MULAKAN"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Seterusnya"</string>
-</resources>
diff --git a/leanback/res/values-my/strings.xml b/leanback/res/values-my/strings.xml
deleted file mode 100644
index 7e7f3fc..0000000
--- a/leanback/res/values-my/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">"MediaPlayer မှားယွင်းမှုကုဒ် %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-nb/strings.xml b/leanback/res/values-nb/strings.xml
deleted file mode 100644
index bdcd016..0000000
--- a/leanback/res/values-nb/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">"Navigasjonsmeny"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Søkehandling"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Søk"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Snakk for å søke"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Søk i <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Snakk for å søke i <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">"Spill av"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Sett på pause"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Fremoverspoling"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Fremoverspoling %1$dX"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Tilbakespoling"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Tilbakespoling %1$dX"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Hopp til neste"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Hopp til forrige"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Flere handlinger"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Fjern valg av tommel opp"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Velg tommel opp"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Fjern valg av tommel ned"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Velg tommel ned"</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Ikke gjenta noen"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Gjenta alle"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Gjenta én"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Aktivér avspilling i tilfeldig rekkefølge"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Deaktiver avspilling i tilfeldig rekkefølge"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Aktivér høy kvalitet"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Deaktiver høy kvalitet"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Aktivér teksting"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Deaktiver teksting"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Slå på modusen Bilde-i-bilde"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Mediekontrollene vises"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Mediekontrollene er skjult – trykk på styrepilene for å vise dem"</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Fullfør"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Fortsett"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"MediaPlayer-feilkode %1$d ekstra %2$d"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"KOM I GANG"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Neste"</string>
-</resources>
diff --git a/leanback/res/values-ne/strings.xml b/leanback/res/values-ne/strings.xml
deleted file mode 100644
index fb071a7..0000000
--- a/leanback/res/values-ne/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">"MediaPlayer को त्रुटि सम्बन्धी कोड %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-nl/strings.xml b/leanback/res/values-nl/strings.xml
deleted file mode 100644
index 7bc122f..0000000
--- a/leanback/res/values-nl/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">"Navigatiemenu"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Actie zoeken"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Zoeken"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Spreek om te zoeken"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> zoeken"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Spreek om in <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> te zoeken"</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">"Afspelen"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Onderbreken"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Vooruitspoelen"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Vooruitspoelen %1$dX"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Terugspoelen"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Terugspoelen %1$dX"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Naar volgende"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Naar vorige"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Meer acties"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Selectie van \'Leuk\' ongedaan maken"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"\'Leuk\' selecteren"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Selectie van \'Niet leuk\' ongedaan maken"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"\'Niet leuk\' selecteren"</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Niet herhalen"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Alles herhalen"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Eén herhalen"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Shuffle inschakelen"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Shuffle uitschakelen"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Hoge kwaliteit inschakelen"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Hoge kwaliteit uitschakelen"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Ondertiteling inschakelen"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Ondertiteling uitschakelen"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Scherm-in-scherm-modus openen"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Opties voor mediabediening worden weergegeven"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Opties voor mediabediening verborgen. Druk op de D-pad om ze weer te geven."</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Voltooien"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Doorgaan"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"Mediaspeler: foutcode %1$d extra %2$d"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"AAN DE SLAG"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Volgende"</string>
-</resources>
diff --git a/leanback/res/values-pa/strings.xml b/leanback/res/values-pa/strings.xml
deleted file mode 100644
index 57956ee..0000000
--- a/leanback/res/values-pa/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">"ਮੀਡੀਆ ਕੰਟਰੋਲ ਲੁਕੇ ਹੋਏ ਹਨ, ਵਿਖਾਉਣ ਲਈ ਡੀ-ਪੈਡ ਦਬਾਓ"</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">"MediaPlayer ਗੜਬੜ ਕੋਡ %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-pl/strings.xml b/leanback/res/values-pl/strings.xml
deleted file mode 100644
index cd6f6ca..0000000
--- a/leanback/res/values-pl/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">"Menu nawigacyjne"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Wyszukaj czynność"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Szukaj"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Powiedz, aby wyszukać"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Szukaj <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Powiedz, co chcesz wyszukać w usłudze <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">"Odtwórz"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Wstrzymaj"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Przewiń do przodu"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Przewiń do przodu %1$dX"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Przewiń do tyłu"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Przewiń do tyłu %1$dX"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Pomiń następny"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Pomiń poprzedni"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Więcej czynności"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Odznacz Lubię"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Zaznacz Lubię"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Odznacz Nie lubię"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Zaznacz Nie lubię"</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Nie powtarzaj"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Powtórz wszystkie"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Powtórz jeden"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Włącz odtwarzanie losowe"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Wyłącz odtwarzanie losowe"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Włącz wysoką jakość"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Wyłącz wysoką jakość"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Włącz napisy"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Wyłącz napisy"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Włącz tryb obrazu w obrazie"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Elementy sterujące multimediami są wyświetlone"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Elementy sterujące multimediami są ukryte. Naciśnij pad kierunkowy, by je wyświetlić"</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Zakończ"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Dalej"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"MediaPlayer – kod błędu %1$d, dodatkowo %2$d"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"ROZPOCZNIJ"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Dalej"</string>
-</resources>
diff --git a/leanback/res/values-pt-rBR/strings.xml b/leanback/res/values-pt-rBR/strings.xml
deleted file mode 100644
index c5f238e..0000000
--- a/leanback/res/values-pt-rBR/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">"Menu de navegação"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Ação de pesquisa"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Pesquisar"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Fale para pesquisar"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Pesquisar <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Fale para pesquisar no <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">"Reproduzir"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Pausar"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Avançar"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Avançar %1$dX"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Retroceder"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Retroceder %1$dX"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Pular próxima"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Pular anterior"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Mais ações"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Desmarcar gostei"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Marcar gostei"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Desmarcar não gostei"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Marcar não gostei"</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Não repetir"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Repetir tudo"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Repetir uma"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Ativar reprodução aleatória"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Desativar reprodução aleatória"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Ativar alta qualidade"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Desativar alta qualidade"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Ativar closed captioning"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Desativar closed captioning"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Entrar no modo Picture in Picture"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Os controles de mídia estão sendo exibidos"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Os controles de mídia estão ocultos. Pressione o botão direcional para exibi-los"</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Concluir"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continuar"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"Código de erro do MediaPlayer %1$d extra %2$d"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"PRIMEIROS PASSOS"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Próximo"</string>
-</resources>
diff --git a/leanback/res/values-pt-rPT/strings.xml b/leanback/res/values-pt-rPT/strings.xml
deleted file mode 100644
index cb5da8a..0000000
--- a/leanback/res/values-pt-rPT/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">"Menu de navegação"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Ação de pesquisa"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Pesquisar"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Fale para pesquisar"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Pesquisar <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Fale para pesquisar no(a) <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">"Reproduzir"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Interromper"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Avançar"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Avançar %1$dX"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Recuar"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Recuar %1$dX"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Avançar para o seguinte"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Avançar para o anterior"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Mais ações"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Desselecionar Gosto"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Selecionar Gosto"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Desselecionar Não gosto"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Selecionar Não gosto"</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Não repetir"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Repetir tudo"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Repetir um"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Ativar reprodução aleatória"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Desativar reprodução aleatória"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Ativar alta qualidade"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Desativar alta qualidade"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Ativar legendas"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Desativar legendas"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Entrar no modo de ecrã no ecrã"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Controlos de multimédia apresentados"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Controlos de multimédia ocultados, prima o teclado direcional para mostrar"</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Concluir"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continuar"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"Código de erro do MediaPlayer %1$d extra %2$d"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"INICIAR"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Seguinte"</string>
-</resources>
diff --git a/leanback/res/values-pt/strings.xml b/leanback/res/values-pt/strings.xml
deleted file mode 100644
index c5f238e..0000000
--- a/leanback/res/values-pt/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">"Menu de navegação"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Ação de pesquisa"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Pesquisar"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Fale para pesquisar"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Pesquisar <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Fale para pesquisar no <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">"Reproduzir"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Pausar"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Avançar"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Avançar %1$dX"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Retroceder"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Retroceder %1$dX"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Pular próxima"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Pular anterior"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Mais ações"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Desmarcar gostei"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Marcar gostei"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Desmarcar não gostei"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Marcar não gostei"</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Não repetir"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Repetir tudo"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Repetir uma"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Ativar reprodução aleatória"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Desativar reprodução aleatória"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Ativar alta qualidade"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Desativar alta qualidade"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Ativar closed captioning"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Desativar closed captioning"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Entrar no modo Picture in Picture"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Os controles de mídia estão sendo exibidos"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Os controles de mídia estão ocultos. Pressione o botão direcional para exibi-los"</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Concluir"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continuar"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"Código de erro do MediaPlayer %1$d extra %2$d"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"PRIMEIROS PASSOS"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Próximo"</string>
-</resources>
diff --git a/leanback/res/values-ro/strings.xml b/leanback/res/values-ro/strings.xml
deleted file mode 100644
index 325632e..0000000
--- a/leanback/res/values-ro/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">"Meniu de navigare"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Acțiunea de căutare"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Căutați"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Rostiți pentru a căuta"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Căutați <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Vorbiți pentru a căuta în <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">"Redă"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Întrerupe"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Derulează rapid înainte"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Derulați rapid înainte cu %1$dX"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Derulează"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Derulați înapoi cu %1$dX"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Ignoră articolul următor"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Ignoră articolul anterior"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Mai multe acțiuni"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Deselectează „Îmi place”"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Selectează „Îmi place”"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Deselectează „Nu-mi place”"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Selectează „Nu-mi place”"</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Nu repetă"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Repetă toate"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Repetă unul"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Activează redarea în mod aleatoriu"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Dezactivează redarea în mod aleatoriu"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Activează calitatea înaltă"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Dezactivează calitatea înaltă"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Activează subtitrările"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Dezactivează subtitrările"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Activați modul Picture-in-Picture"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Comenzile media sunt afișate"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Comenzile media sunt ascunse. Apăsați pe butonul direcțional pentru a le afișa."</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Finalizați"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continuați"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"Cod de eroare MediaPlayer %1$d suplimentar %2$d"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"ÎNCEPEȚI"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Înainte"</string>
-</resources>
diff --git a/leanback/res/values-ru/strings.xml b/leanback/res/values-ru/strings.xml
deleted file mode 100644
index 8631587..0000000
--- a/leanback/res/values-ru/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/res/values-si/strings.xml b/leanback/res/values-si/strings.xml
deleted file mode 100644
index 1f74070..0000000
--- a/leanback/res/values-si/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">"MediaPlayer දෝෂ කේතය %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-sk/strings.xml b/leanback/res/values-sk/strings.xml
deleted file mode 100644
index 45dc5bb..0000000
--- a/leanback/res/values-sk/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">"Navigačná ponuka"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Akcia vyhľadávania"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Hľadať"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Hovorením spustíte vyhľadávanie"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Vyhľadať výraz <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Hovorte na vyhľadávanie v kontexte <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">"Prehrať"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Pozastaviť"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Pretočiť dopredu"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Pretočiť dopredu %1$dX"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Pretočiť späť"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Pretočiť späť %1$dX"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Prejsť na ďalšiu položku"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Prejsť na predchádzajúcu položku"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Viac akcií"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Zrušiť Páči sa mi"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Vybrať Páči sa mi"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Zrušiť Nepáči sa mi"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Vybrať Nepáči sa mi"</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Neopakovať"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Opakovať všetko"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Opakovať jednu položku"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Zapnúť náhodné prehrávanie"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Vypnúť náhodné prehrávanie"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Povoliť médiá vo vysokej kvalite"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Zakázať médiá vo vysokej kvalite"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Zapnúť skryté titulky"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Vypnúť skryté titulky"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Prejsť do režimu obraz v obraze"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Ovládacie prvky médií sa zobrazujú"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Ovládacie prvky médií sú skryté, zobrazíte ich stlačením krížového ovládača"</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Dokončiť"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Pokračovať"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"Kód chyby MediaPlayer %1$d extra %2$d"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"ZAČÍNAME"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Ďalej"</string>
-</resources>
diff --git a/leanback/res/values-sl/strings.xml b/leanback/res/values-sl/strings.xml
deleted file mode 100644
index d8f9712..0000000
--- a/leanback/res/values-sl/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">"Meni za krmarjenje"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Dejanje iskanja"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Iskanje"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Izgovorite iskalno poizvedbo"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Iskanje: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Izgovorite poizvedbo za iskanje v storitvi <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$d-kratno"</string>
-    <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$d-kratno"</string>
-    <string name="lb_playback_controls_play" msgid="731953341987346903">"Predvajaj"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Zaustavi"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Previj naprej"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Hitro previjanje naprej – %1$d-kratno"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Previj nazaj"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Previjanje nazaj – %1$d-kratno"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Preskoči naslednje"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Preskoči prejšnje"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Več dejanj"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Prekliči izbor palca gor"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Izberi palec gor"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Prekliči izbor palca dol"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Izberi palec dol"</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Ne ponovi"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Ponovi vse"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Ponovi eno"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Omogoči naključno predvajanje"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Onemogoči naključno predvajanje"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Omogoči visoko kakovost"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Onemogoči visoko kakovost"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Omogoči podnapise"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Onemogoči podnapise"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Vklop načina za sliko v sliki"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Kontrolniki predstavnosti so prikazani"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Kontrolniki predstavnosti so skriti, za prikaz pritisnite smerni gumb"</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Dokončaj"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Naprej"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"Koda napake MediaPlayer %1$d dodatno %2$d"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"ZAČNITE"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Naprej"</string>
-</resources>
diff --git a/leanback/res/values-sq/strings.xml b/leanback/res/values-sq/strings.xml
deleted file mode 100644
index e466bcc..0000000
--- a/leanback/res/values-sq/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">"Menyja e navigimit"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Veprim i kërkimit"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Kërko"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Fol për të kërkuar"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Kërko për <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Fol për të kërkuar <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">"Luaj"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Pauzë"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Përparo me shpejtësi"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Përparo me shpejtësi %1$dX"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Kthe në fillim"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Kthe në fillim %1$dX"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Kapërce për te tjetra"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Kapërce të mëparshmin"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Veprime të tjera"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Hiq nga përzgjedhja \"Gishti lart\""</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Përzgjidh \"Gishtin sipër\""</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Hiq nga përzgjedhja \"Gishti poshtë\""</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Përzgjidh \"Gishtin poshtë\""</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Mos përsërit asnjë"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Përsërit të gjitha"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Përsërit një"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Aktivizo përzierjen"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Çaktivizo përzierjen"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Aktivizo \"Cilësinë e lartë\""</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Çaktivizo \"Cilësinë e lartë\""</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Aktivizo titrat"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Çaktivizo titrat me sekuencë kohore"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Aktivizo modalitetin e figurës brenda figurës"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Kontrollet e medias të shfaqura"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Kontrollet e medias të fshehura, shtyp bllokun e drejtimit për t\'i shfaqur"</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Përfundo"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Vazhdo"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"Kodi i gabimit i MediaPlayer %1$d shtesa %2$d"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"FILLO"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Përpara"</string>
-</resources>
diff --git a/leanback/res/values-sr/strings.xml b/leanback/res/values-sr/strings.xml
deleted file mode 100644
index 705aafe..0000000
--- a/leanback/res/values-sr/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">"Контроле за медије су скривене, притисните контроле за кретање да бисте их приказали"</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">"Кôд грешке MediaPlayer-а %1$d extra %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-sv/strings.xml b/leanback/res/values-sv/strings.xml
deleted file mode 100644
index d528d53..0000000
--- a/leanback/res/values-sv/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">"Navigationsmeny"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Sökåtgärd"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Sök"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Säg det du söker efter"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Sök i <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Tala för att söka i <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">"Spela upp"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Pausa"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Snabbspola framåt"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Spola framåt %1$dX"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Spola tillbaka"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Spola tillbaka %1$dX"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Hoppa till nästa"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Hoppa till föregående"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Fler åtgärder"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Avmarkera tummen upp"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Markera tummen upp"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Avmarkera tummen ned"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Markera tummen ned"</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Upprepa inga"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Upprepa alla"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Upprepa en"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Blanda spår"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Blanda inte spår"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Aktivera hög kvalitet"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Inaktivera hög kvalitet"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Aktivera textning"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Inaktivera textning"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Ange läget Bild-i-bild"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Mediakontrollerna visas"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Mediakontrollerna är dolda och visas om du trycker på styrkorset"</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Slutför"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Fortsätt"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"Felkod för MediaPlayer %1$d extra %2$d"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"KOM IGÅNG"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Nästa"</string>
-</resources>
diff --git a/leanback/res/values-sw/strings.xml b/leanback/res/values-sw/strings.xml
deleted file mode 100644
index 0fd91a3..0000000
--- a/leanback/res/values-sw/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">"Menyu ya kusogeza"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Kitendo cha Kutafuta"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Utafutaji"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Tamka ili utafute"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Tafuta <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Tamka ili utafute kwenye <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">"Google Play"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Sitisha"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Peleka mbele Haraka"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Peleka Mbele %1$dX"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Rudisha nyuma"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Peleka nyuma %1$dX"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Ruka Inayofuata"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Ruka Iliyotangulia"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Vitendo zaidi"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Ondoa Uteuzi wa Bomba"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Teua Bomba"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Ondoa Uteuzi wa Si Bomba"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Teua Si Bomba"</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Usirudie Yoyote"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Rudia zote"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Rudia Moja"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Washa Kuchanganya"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Zima Kuchanganya"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Washa Ubora wa Juu"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Zima Ubora wa Juu"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Washa manukuu"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Zima manukuu"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Weka Hali ya Picha ndani ya Picha Nyingine"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Inaonyesha udhibiti wa maudhui"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Imeficha udhibiti wa maudhui, bonyeza d-pad ili uuonyeshe"</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Kamilisha"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Endelea"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"Msimbo wa hitilafu wa Kichezaji Maudhui %1$d %2$d zaidi"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"ANZA KUTUMIA"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Endelea"</string>
-</resources>
diff --git a/leanback/res/values-ta/strings.xml b/leanback/res/values-ta/strings.xml
deleted file mode 100644
index 0d2b216..0000000
--- a/leanback/res/values-ta/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">"மீடியா கட்டுப்பாடுகள் மறைக்கப்பட்டுள்ளன. கட்டுப்பாடுகளைக் காட்ட, டிபேடை அழுத்தவும்"</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">"MediaPlayer பிழைக் குறியீடு: %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-te/strings.xml b/leanback/res/values-te/strings.xml
deleted file mode 100644
index 5188d19..0000000
--- a/leanback/res/values-te/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-ప్యాడ్ నొక్కండి"</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">"MediaPlayer ఎర్రర్ కోడ్ %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-th/strings.xml b/leanback/res/values-th/strings.xml
deleted file mode 100644
index 1e291f5..0000000
--- a/leanback/res/values-th/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">"รหัสข้อผิดพลาด MediaPlayer %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-tl/strings.xml b/leanback/res/values-tl/strings.xml
deleted file mode 100644
index 5ecef2d..0000000
--- a/leanback/res/values-tl/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">"Menu ng navigation"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Pagkilos sa Paghahanap"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Maghanap"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Magsalita upang maghanap"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Hanapin ang <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Magsalita upang maghanap sa <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">"I-play"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"I-pause"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"I-fast Forward"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"I-fast Forward %1$dX"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"I-rewind"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"I-rewind %1$dX"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Laktawan ang Susunod"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Laktawan ang Nakaraan"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Higit Pang Mga Pagkilos"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Alisin sa Pagkakapili ang Thumb Up"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Piliin ang Thumb Up"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Alisin sa Pagkakapili ang Thumb Down"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Piliin ang Thumb Down"</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Walang Uulitin"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Ulitin Lahat"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Ulitin ang Isa"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"I-enable ang Shuffle"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"I-disable ang Shuffle"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"I-enable ang Mataas na Kalidad"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"I-disable ang Mataas na Kalidad"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"I-enable ang Paglalagay ng Subtitle"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"I-disable ang Paglalagay ng Subtitle"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Pumasok sa Picture In Picture Mode"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Ipinapakita ang mga kontrol ng media"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Nakatago ang mga kontrol ng media, pindutin ang d-pad upang ipakita"</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Tapusin"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Magpatuloy"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"Code ng error na %1$d ng MediaPlayer na may extra na %2$d"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"MAGSIMULA"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Susunod"</string>
-</resources>
diff --git a/leanback/res/values-tr/strings.xml b/leanback/res/values-tr/strings.xml
deleted file mode 100644
index d47e752..0000000
--- a/leanback/res/values-tr/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">"Gezinme menüsü"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Arama İşlemi"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Ara"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Arama yapmak için konuşun"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Ara: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Konuşarak <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> araması yapın"</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">"Oynat"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Duraklat"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"İleri Sar"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"%1$dX İleri Sar"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Geri Sar"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"%1$dX Geri Sar"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Sonrakine Atla"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Öncekine Atla"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Diğer İşlemler"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Beğenme Seçimini Kaldır"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Beğenmeyi Seç"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Beğenmeme Seçimini Kaldır"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Beğenmemeyi Seç"</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Hiçbirini Tekrarlama"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Tümünü Tekrarla"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Birini Tekrarla"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Karıştırmayı Etkinleştir"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Karıştırmayı Devre Dışı Bırak"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Yüksek Kalitede Oynatmayı Etkinleştir"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Yüksek Kalitede Oynatmayı Devre Dışı Bırak"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Altyazıları Etkinleştir"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Altyazıları Devre Dışı Bırak"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Pencere İçinde Pencere Moduna Geç"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"."</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Medya denetimleri gösteriliyor"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Medya denetimleri gizli durumda. Görüntülemek için d-pad\'e basın."</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Son"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Devam"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"MediaPlayer hata kodu %1$d ekstra %2$d"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"BAŞLA"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Sonraki"</string>
-</resources>
diff --git a/leanback/res/values-uk/strings.xml b/leanback/res/values-uk/strings.xml
deleted file mode 100644
index 12a9ebf..0000000
--- a/leanback/res/values-uk/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">"Елементи керування медіа сховано. Натисніть цифрову панель, щоб показати їх"</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">"Код помилки MediaPlayer: %1$d extra %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-ur/strings.xml b/leanback/res/values-ur/strings.xml
deleted file mode 100644
index c9dc013..0000000
--- a/leanback/res/values-ur/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/res/values-uz/strings.xml b/leanback/res/values-uz/strings.xml
deleted file mode 100644
index ab6542d..0000000
--- a/leanback/res/values-uz/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">"Navigatsiya menyusi"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Qidiruv amali"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Qidirish"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Qidirish uchun gapiring"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Qidirish: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Qidirish uchun ayting: <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">"Ijro qilish"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"To‘xtatib turish"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Oldinga o‘tkazish"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"%1$dX tezlikda oldinga o‘tkazish"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Orqaga o‘tkazish"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"%1$dX tezlikda orqaga qaytarish"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Keyingisiga o‘tish"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Avvalgisiga qaytish"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Boshqa amallar"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Ijobiy baho tanlovini bekor qilish"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Ijobiy bahoni tanlash"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Salbiy baho tanlovini bekor qilish"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Salbiy bahoni tanlash"</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Takrorlamaslik"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Barchasini takrorlash"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Bir marta takrorlash"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Aralashtirish funksiyasini yoqish"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Aralashtirish funksiyasini o‘chirish"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Yuqori sifatni yoqish"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Yuqori sifatni o‘chirib qo‘yish"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Taglavhalarni yoqish"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Taglavhalarni o‘chirib qo‘yish"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Tasvir ustida tasvir rejimiga kirish"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Boshqaruv elementlari ochiq"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Boshqaruv elementlari berkitilgan, ochish uchun D-pad tugmasini bosing"</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Tugatish"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Davom etish"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"Media pleyer xatoligi kodi: %1$d (yana: %2$d)"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"BOSHLADIK"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Keyingisi"</string>
-</resources>
diff --git a/leanback/res/values-vi/strings.xml b/leanback/res/values-vi/strings.xml
deleted file mode 100644
index cb0a2d8..0000000
--- a/leanback/res/values-vi/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">"Menu điều hướng"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Tác vụ tìm kiếm"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Tìm kiếm"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Nói để tìm kiếm"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Tìm kiếm <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Nói để tìm kiếm trên <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">"Phát"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Tạm dừng"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Tua nhanh"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Tua đi %1$dX"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Tua lại"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Tua lại %1$dX"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Chuyển đến mục tiếp theo"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Chuyển về mục trước"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Tác vụ khác"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Bỏ chọn thích"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Chọn thích"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Bỏ chọn không thích"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Chọn không thích"</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Không lặp lại"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Lặp lại tất cả"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Lặp lại một mục"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Bật phát ngẫu nhiên"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Tắt phát ngẫu nhiên"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Bật chế độ chất lượng cao"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Tắt chế độ chất lượng cao"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Bật phụ đề"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Tắt phụ đề"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Vào chế độ ảnh trong ảnh"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Điều khiển phương tiện được hiển thị"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Điều khiển phương tiện bị ẩn, nhấn d-pad để hiển thị"</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Hoàn tất"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Tiếp tục"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"Mã lỗi MediaPlayer %1$d %2$d bổ sung"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"BẮT ĐẦU"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Tiếp theo"</string>
-</resources>
diff --git a/leanback/res/values-zh-rCN/strings.xml b/leanback/res/values-zh-rCN/strings.xml
deleted file mode 100644
index 2af9dba..0000000
--- a/leanback/res/values-zh-rCN/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$d 倍速"</string>
-    <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$d 倍速"</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$d 倍速快进"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"快退"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"%1$d 倍速快退"</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">"MediaPlayer 错误代码:%1$d extra %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-zh-rHK/strings.xml b/leanback/res/values-zh-rHK/strings.xml
deleted file mode 100644
index 9080408..0000000
--- a/leanback/res/values-zh-rHK/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">"畫面已隱藏媒體控制項,按十字鍵即可顯示"</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">"MediaPlayer 錯誤代碼:%1$d extra %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-zh-rTW/strings.xml b/leanback/res/values-zh-rTW/strings.xml
deleted file mode 100644
index d48be55..0000000
--- a/leanback/res/values-zh-rTW/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">"MediaPlayer 錯誤代碼:%1$d extra %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-zu/strings.xml b/leanback/res/values-zu/strings.xml
deleted file mode 100644
index 06f5641..0000000
--- a/leanback/res/values-zu/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">"Imenyu yokuzulazula"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"Isenzo sokusesha"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"Sesha"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Khuluma ukuze useshe"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Sesha i-<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Khuluma ukuze useshe i-<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">"Dlala"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Misa isikhashana"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Iya phambili ngokushesha"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Mikisa phambili ngokushesha i-%1$dX"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Buyisela emuva"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Mikisa emuva i-%1$dX"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Yeqa okulandelayo"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Yeqa kwangaphambilini"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Izenzo eziningi"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Susa ukukhetha isithupha saphezulu"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Khetha isithupha saphezulu"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Susa ukukhetha isithupha saphansi"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Khetha isithupha saphansi"</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Ungaphindi lutho"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Phinda konke"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Phida okukodwa"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Nika amandla ukushova"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Khubaza ukushova"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Nika amandla ikhwalithi ephezulu"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Khubaza ikhwalithi ephezulu"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Nika amandla imibhalo engezansi"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Khubaza imihbalo engezansi"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Ngena isithombe kumodi yesithombe"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Izilawuli zemidiya zibonisiwe"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Izilawuli zemidiya zifihliwe, cindezela ku-d-pad ukuze uzibonise"</string>
-    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Qeda"</string>
-    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Qhubeka"</string>
-    <string name="lb_media_player_error" msgid="3650250994187305396">"Ikhodi yephutha le-MediaPlayer %1$d extra %2$d"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"QALISA"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Okulandelayo"</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/StaggeredGridDefault.java b/leanback/src/android/support/v17/leanback/widget/StaggeredGridDefault.java
deleted file mode 100644
index f4c0141..0000000
--- a/leanback/src/android/support/v17/leanback/widget/StaggeredGridDefault.java
+++ /dev/null
@@ -1,430 +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;
-
-/**
- * A default implementation of {@link StaggeredGrid}.
- *
- * This implementation tries to fill items in consecutive row order. The next
- * item is always in same row or in the next row.
- */
-final class StaggeredGridDefault extends StaggeredGrid {
-
-    /**
-     * Returns the max edge value of item (visible or cached) in a row.  This
-     * will be the place to append or prepend item not in cache.
-     */
-    int getRowMax(int rowIndex) {
-        if (mFirstVisibleIndex < 0) {
-            return Integer.MIN_VALUE;
-        }
-        if (mReversedFlow) {
-            int edge = mProvider.getEdge(mFirstVisibleIndex);
-            if (getLocation(mFirstVisibleIndex).row == rowIndex) {
-                return edge;
-            }
-            for (int i = mFirstVisibleIndex + 1; i <= getLastIndex(); i++) {
-                Location loc = getLocation(i);
-                edge += loc.offset;
-                if (loc.row == rowIndex) {
-                    return edge;
-                }
-            }
-        } else {
-            int edge = mProvider.getEdge(mLastVisibleIndex);
-            Location loc = getLocation(mLastVisibleIndex);
-            if (loc.row == rowIndex) {
-                return edge + loc.size;
-            }
-            for (int i = mLastVisibleIndex - 1; i >= getFirstIndex(); i--) {
-                edge -= loc.offset;
-                loc = getLocation(i);
-                if (loc.row == rowIndex) {
-                    return edge + loc.size;
-                }
-            }
-        }
-        return Integer.MIN_VALUE;
-    }
-
-    /**
-     * Returns the min edge value of item (visible or cached) in a row.  This
-     * will be the place to prepend or append item not in cache.
-     */
-    int getRowMin(int rowIndex) {
-        if (mFirstVisibleIndex < 0) {
-            return Integer.MAX_VALUE;
-        }
-        if (mReversedFlow) {
-            int edge = mProvider.getEdge(mLastVisibleIndex);
-            Location loc = getLocation(mLastVisibleIndex);
-            if (loc.row == rowIndex) {
-                return edge - loc.size;
-            }
-            for (int i = mLastVisibleIndex - 1; i >= getFirstIndex(); i--) {
-                edge -= loc.offset;
-                loc = getLocation(i);
-                if (loc.row == rowIndex) {
-                    return edge - loc.size;
-                }
-            }
-        } else {
-            int edge = mProvider.getEdge(mFirstVisibleIndex);
-            if (getLocation(mFirstVisibleIndex).row == rowIndex) {
-                return edge;
-            }
-            for (int i = mFirstVisibleIndex + 1; i <= getLastIndex() ; i++) {
-                Location loc = getLocation(i);
-                edge += loc.offset;
-                if (loc.row == rowIndex) {
-                    return edge;
-                }
-            }
-        }
-        return Integer.MAX_VALUE;
-    }
-
-    /**
-     * Note this method has assumption that item is filled either in the same row
-     * next row of last item.  Search until row index wrapped.
-     */
-    @Override
-    public int findRowMax(boolean findLarge, int indexLimit, int[] indices) {
-        int value;
-        int edge = mProvider.getEdge(indexLimit);
-        Location loc = getLocation(indexLimit);
-        int row = loc.row;
-        int index = indexLimit;
-        int visitedRows = 1;
-        int visitRow = row;
-        if (mReversedFlow) {
-            value = edge;
-            for (int i = indexLimit + 1; visitedRows < mNumRows && i <= mLastVisibleIndex; i++) {
-                loc = getLocation(i);
-                edge += loc.offset;
-                if (loc.row != visitRow) {
-                    visitRow = loc.row;
-                    visitedRows++;
-                    if (findLarge ? edge > value : edge < value) {
-                        row = visitRow;
-                        value = edge;
-                        index = i;
-                    }
-                }
-            }
-        } else {
-            value = edge + mProvider.getSize(indexLimit);
-            for (int i = indexLimit - 1; visitedRows < mNumRows && i >= mFirstVisibleIndex; i--) {
-                edge -= loc.offset;
-                loc = getLocation(i);
-                if (loc.row != visitRow) {
-                    visitRow = loc.row;
-                    visitedRows++;
-                    int newValue = edge + mProvider.getSize(i);
-                    if (findLarge ? newValue > value : newValue < value) {
-                        row = visitRow;
-                        value = newValue;
-                        index = i;
-                    }
-                }
-            }
-        }
-        if (indices != null) {
-            indices[0] = row;
-            indices[1] = index;
-        }
-        return value;
-    }
-
-    /**
-     * Note this method has assumption that item is filled either in the same row
-     * next row of last item.  Search until row index wrapped.
-     */
-    @Override
-    public int findRowMin(boolean findLarge, int indexLimit, int[] indices) {
-        int value;
-        int edge = mProvider.getEdge(indexLimit);
-        Location loc = getLocation(indexLimit);
-        int row = loc.row;
-        int index = indexLimit;
-        int visitedRows = 1;
-        int visitRow = row;
-        if (mReversedFlow) {
-            value = edge - mProvider.getSize(indexLimit);
-            for (int i = indexLimit - 1; visitedRows < mNumRows && i >= mFirstVisibleIndex; i--) {
-                edge -= loc.offset;
-                loc = getLocation(i);
-                if (loc.row != visitRow) {
-                    visitRow = loc.row;
-                    visitedRows++;
-                    int newValue = edge - mProvider.getSize(i);
-                    if (findLarge ? newValue > value : newValue < value) {
-                        value = newValue;
-                        row = visitRow;
-                        index = i;
-                    }
-                }
-            }
-        } else {
-            value = edge;
-            for (int i = indexLimit + 1; visitedRows < mNumRows && i <= mLastVisibleIndex; i++) {
-                loc = getLocation(i);
-                edge += loc.offset;
-                if (loc.row != visitRow) {
-                    visitRow = loc.row;
-                    visitedRows++;
-                    if (findLarge ? edge > value : edge < value) {
-                        value = edge;
-                        row = visitRow;
-                        index = i;
-                    }
-                }
-            }
-        }
-        if (indices != null) {
-            indices[0] = row;
-            indices[1] = index;
-        }
-        return value;
-    }
-
-    private int findRowEdgeLimitSearchIndex(boolean append) {
-        boolean wrapped = false;
-        if (append) {
-            for (int index = mLastVisibleIndex; index >= mFirstVisibleIndex; index--) {
-                int row = getLocation(index).row;
-                if (row == 0) {
-                    wrapped = true;
-                } else if (wrapped && row == mNumRows - 1) {
-                    return index;
-                }
-            }
-        } else {
-            for (int index = mFirstVisibleIndex; index <= mLastVisibleIndex; index++) {
-                int row = getLocation(index).row;
-                if (row == mNumRows - 1) {
-                    wrapped = true;
-                } else if (wrapped && row == 0) {
-                    return index;
-                }
-            }
-        }
-        return -1;
-    }
-
-    @Override
-    protected boolean appendVisibleItemsWithoutCache(int toLimit, boolean oneColumnMode) {
-        final int count = mProvider.getCount();
-        int itemIndex;
-        int rowIndex;
-        int edgeLimit;
-        boolean edgeLimitIsValid;
-        if (mLastVisibleIndex >= 0) {
-            if (mLastVisibleIndex < getLastIndex()) {
-                // should fill using cache instead
-                return false;
-            }
-            itemIndex = mLastVisibleIndex + 1;
-            rowIndex = getLocation(mLastVisibleIndex).row;
-            // find start item index of "previous column"
-            int edgeLimitSearchIndex = findRowEdgeLimitSearchIndex(true);
-            if (edgeLimitSearchIndex < 0) {
-                // if "previous column" is not found, using edgeLimit of
-                // first row currently in grid
-                edgeLimit = Integer.MIN_VALUE;
-                for (int i = 0; i < mNumRows; i++) {
-                    edgeLimit = mReversedFlow ? getRowMin(i) : getRowMax(i);
-                    if (edgeLimit != Integer.MIN_VALUE) {
-                        break;
-                    }
-                }
-            } else {
-                edgeLimit = mReversedFlow ? findRowMin(false, edgeLimitSearchIndex, null) :
-                        findRowMax(true, edgeLimitSearchIndex, null);
-            }
-            if (mReversedFlow ? getRowMin(rowIndex) <= edgeLimit
-                    : getRowMax(rowIndex) >= edgeLimit) {
-                // if current row exceeds previous column, fill from next row
-                rowIndex = rowIndex + 1;
-                if (rowIndex == mNumRows) {
-                    // start a new column and using edge limit of current column
-                    rowIndex = 0;
-                    edgeLimit = mReversedFlow ? findRowMin(false, null) : findRowMax(true, null);
-                }
-            }
-            edgeLimitIsValid = true;
-        } else {
-            itemIndex = mStartIndex != START_DEFAULT ? mStartIndex : 0;
-            // if there are cached items,  put on next row of last cached item.
-            rowIndex = (mLocations.size() > 0 ? getLocation(getLastIndex()).row + 1 : itemIndex)
-                    % mNumRows;
-            edgeLimit = 0;
-            edgeLimitIsValid = false;
-        }
-
-        boolean filledOne = false;
-        while (true) {
-            // find end-most row edge (.high is biggest, or .low is smallest in reversed flow)
-            // fill from current row till last row so that each row will grow longer than
-            // the previous highest row.
-            for (; rowIndex < mNumRows; rowIndex++) {
-                // fill one item to a row
-                if (itemIndex == count || (!oneColumnMode && checkAppendOverLimit(toLimit))) {
-                    return filledOne;
-                }
-                int location = mReversedFlow ? getRowMin(rowIndex) : getRowMax(rowIndex);
-                if (location == Integer.MAX_VALUE || location == Integer.MIN_VALUE) {
-                    // nothing on the row
-                    if (rowIndex == 0) {
-                        location = mReversedFlow ? getRowMin(mNumRows - 1) : getRowMax(mNumRows - 1);
-                        if (location != Integer.MAX_VALUE && location != Integer.MIN_VALUE) {
-                            location = location + (mReversedFlow ? -mSpacing : mSpacing);
-                        }
-                    } else {
-                        location = mReversedFlow ? getRowMax(rowIndex - 1) : getRowMin(rowIndex - 1);
-                    }
-                } else {
-                    location = location + (mReversedFlow ? -mSpacing : mSpacing);
-                }
-                int size = appendVisibleItemToRow(itemIndex++, rowIndex, location);
-                filledOne = true;
-                // fill more item to the row to make sure this row is longer than
-                // the previous highest row.
-                if (edgeLimitIsValid) {
-                    while (mReversedFlow ? location - size > edgeLimit :
-                            location + size < edgeLimit) {
-                        if (itemIndex == count || (!oneColumnMode && checkAppendOverLimit(toLimit))) {
-                            return filledOne;
-                        }
-                        location = location + (mReversedFlow ? - size - mSpacing : size + mSpacing);
-                        size = appendVisibleItemToRow(itemIndex++, rowIndex, location);
-                    }
-                } else {
-                    edgeLimitIsValid = true;
-                    edgeLimit = mReversedFlow ? getRowMin(rowIndex) : getRowMax(rowIndex);
-                }
-            }
-            if (oneColumnMode) {
-                return filledOne;
-            }
-            edgeLimit = mReversedFlow ? findRowMin(false, null) : findRowMax(true, null);
-            // start fill from row 0 again
-            rowIndex = 0;
-        }
-    }
-
-    @Override
-    protected boolean prependVisibleItemsWithoutCache(int toLimit, boolean oneColumnMode) {
-        int itemIndex;
-        int rowIndex;
-        int edgeLimit;
-        boolean edgeLimitIsValid;
-        if (mFirstVisibleIndex >= 0) {
-            if (mFirstVisibleIndex > getFirstIndex()) {
-                // should fill using cache instead
-                return false;
-            }
-            itemIndex = mFirstVisibleIndex - 1;
-            rowIndex = getLocation(mFirstVisibleIndex).row;
-            // find start item index of "previous column"
-            int edgeLimitSearchIndex = findRowEdgeLimitSearchIndex(false);
-            if (edgeLimitSearchIndex < 0) {
-                // if "previous column" is not found, using edgeLimit of
-                // last row currently in grid and fill from upper row
-                rowIndex = rowIndex - 1;
-                edgeLimit = Integer.MAX_VALUE;
-                for (int i = mNumRows - 1; i >= 0; i--) {
-                    edgeLimit = mReversedFlow ? getRowMax(i) : getRowMin(i);
-                    if (edgeLimit != Integer.MAX_VALUE) {
-                        break;
-                    }
-                }
-            } else {
-                edgeLimit = mReversedFlow ? findRowMax(true, edgeLimitSearchIndex, null) :
-                        findRowMin(false, edgeLimitSearchIndex, null);
-            }
-            if (mReversedFlow ? getRowMax(rowIndex) >= edgeLimit
-                    : getRowMin(rowIndex) <= edgeLimit) {
-                // if current row exceeds previous column, fill from next row
-                rowIndex = rowIndex - 1;
-                if (rowIndex < 0) {
-                    // start a new column and using edge limit of current column
-                    rowIndex = mNumRows - 1;
-                    edgeLimit = mReversedFlow ? findRowMax(true, null) :
-                            findRowMin(false, null);
-                }
-            }
-            edgeLimitIsValid = true;
-        } else {
-            itemIndex = mStartIndex != START_DEFAULT ? mStartIndex : 0;
-            // if there are cached items,  put on previous row of first cached item.
-            rowIndex = (mLocations.size() >= 0 ? getLocation(getFirstIndex()).row + mNumRows - 1
-                    : itemIndex) % mNumRows;
-            edgeLimit = 0;
-            edgeLimitIsValid = false;
-        }
-        boolean filledOne = false;
-        while (true) {
-            // find start-most row edge (.low is smallest, or .high is largest in reversed flow)
-            // fill from current row till first row so that each row will grow longer than
-            // the previous lowest row.
-            for (; rowIndex >= 0; rowIndex--) {
-                // fill one item to a row
-                if (itemIndex < 0 || (!oneColumnMode && checkPrependOverLimit(toLimit))) {
-                    return filledOne;
-                }
-                int location = mReversedFlow ? getRowMax(rowIndex) : getRowMin(rowIndex);
-                if (location == Integer.MAX_VALUE || location == Integer.MIN_VALUE) {
-                    // nothing on the row
-                    if (rowIndex == mNumRows - 1) {
-                        location = mReversedFlow ? getRowMax(0) : getRowMin(0);
-                        if (location != Integer.MAX_VALUE && location != Integer.MIN_VALUE) {
-                            location = location + (mReversedFlow ? mSpacing : -mSpacing);
-                        }
-                    } else {
-                        location = mReversedFlow ? getRowMin(rowIndex + 1) : getRowMax(rowIndex + 1);
-                    }
-                } else {
-                    location = location + (mReversedFlow ? mSpacing : -mSpacing);
-                }
-                int size = prependVisibleItemToRow(itemIndex--, rowIndex, location);
-                filledOne = true;
-
-                // fill more item to the row to make sure this row is longer than
-                // the previous highest row.
-                if (edgeLimitIsValid) {
-                    while (mReversedFlow ? location + size < edgeLimit :
-                            location - size > edgeLimit) {
-                        if (itemIndex < 0 || (!oneColumnMode && checkPrependOverLimit(toLimit))) {
-                            return filledOne;
-                        }
-                        location = location + (mReversedFlow ? size + mSpacing : -size - mSpacing);
-                        size = prependVisibleItemToRow(itemIndex--, rowIndex, location);
-                    }
-                } else {
-                    edgeLimitIsValid = true;
-                    edgeLimit = mReversedFlow ? getRowMax(rowIndex) : getRowMin(rowIndex);
-                }
-            }
-            if (oneColumnMode) {
-                return filledOne;
-            }
-            edgeLimit = mReversedFlow ? findRowMax(true, null) : findRowMin(false, null);
-            // start fill from last row again
-            rowIndex = mNumRows - 1;
-        }
-    }
-
-
-}
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/AndroidManifest.xml b/leanback/src/main/AndroidManifest.xml
similarity index 100%
rename from leanback/AndroidManifest.xml
rename to leanback/src/main/AndroidManifest.xml
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/main/java/android/support/v17/leanback/widget/StaggeredGridDefault.java b/leanback/src/main/java/android/support/v17/leanback/widget/StaggeredGridDefault.java
new file mode 100644
index 0000000..397fd12
--- /dev/null
+++ b/leanback/src/main/java/android/support/v17/leanback/widget/StaggeredGridDefault.java
@@ -0,0 +1,430 @@
+/*
+ * 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;
+
+/**
+ * A default implementation of {@link StaggeredGrid}.
+ *
+ * This implementation tries to fill items in consecutive row order. The next
+ * item is always in same row or in the next row.
+ */
+final class StaggeredGridDefault extends StaggeredGrid {
+
+    /**
+     * Returns the max edge value of item (visible or cached) in a row.  This
+     * will be the place to append or prepend item not in cache.
+     */
+    int getRowMax(int rowIndex) {
+        if (mFirstVisibleIndex < 0) {
+            return Integer.MIN_VALUE;
+        }
+        if (mReversedFlow) {
+            int edge = mProvider.getEdge(mFirstVisibleIndex);
+            if (getLocation(mFirstVisibleIndex).row == rowIndex) {
+                return edge;
+            }
+            for (int i = mFirstVisibleIndex + 1; i <= getLastIndex(); i++) {
+                Location loc = getLocation(i);
+                edge += loc.offset;
+                if (loc.row == rowIndex) {
+                    return edge;
+                }
+            }
+        } else {
+            int edge = mProvider.getEdge(mLastVisibleIndex);
+            Location loc = getLocation(mLastVisibleIndex);
+            if (loc.row == rowIndex) {
+                return edge + loc.size;
+            }
+            for (int i = mLastVisibleIndex - 1; i >= getFirstIndex(); i--) {
+                edge -= loc.offset;
+                loc = getLocation(i);
+                if (loc.row == rowIndex) {
+                    return edge + loc.size;
+                }
+            }
+        }
+        return Integer.MIN_VALUE;
+    }
+
+    /**
+     * Returns the min edge value of item (visible or cached) in a row.  This
+     * will be the place to prepend or append item not in cache.
+     */
+    int getRowMin(int rowIndex) {
+        if (mFirstVisibleIndex < 0) {
+            return Integer.MAX_VALUE;
+        }
+        if (mReversedFlow) {
+            int edge = mProvider.getEdge(mLastVisibleIndex);
+            Location loc = getLocation(mLastVisibleIndex);
+            if (loc.row == rowIndex) {
+                return edge - loc.size;
+            }
+            for (int i = mLastVisibleIndex - 1; i >= getFirstIndex(); i--) {
+                edge -= loc.offset;
+                loc = getLocation(i);
+                if (loc.row == rowIndex) {
+                    return edge - loc.size;
+                }
+            }
+        } else {
+            int edge = mProvider.getEdge(mFirstVisibleIndex);
+            if (getLocation(mFirstVisibleIndex).row == rowIndex) {
+                return edge;
+            }
+            for (int i = mFirstVisibleIndex + 1; i <= getLastIndex() ; i++) {
+                Location loc = getLocation(i);
+                edge += loc.offset;
+                if (loc.row == rowIndex) {
+                    return edge;
+                }
+            }
+        }
+        return Integer.MAX_VALUE;
+    }
+
+    /**
+     * Note this method has assumption that item is filled either in the same row
+     * next row of last item.  Search until row index wrapped.
+     */
+    @Override
+    public int findRowMax(boolean findLarge, int indexLimit, int[] indices) {
+        int value;
+        int edge = mProvider.getEdge(indexLimit);
+        Location loc = getLocation(indexLimit);
+        int row = loc.row;
+        int index = indexLimit;
+        int visitedRows = 1;
+        int visitRow = row;
+        if (mReversedFlow) {
+            value = edge;
+            for (int i = indexLimit + 1; visitedRows < mNumRows && i <= mLastVisibleIndex; i++) {
+                loc = getLocation(i);
+                edge += loc.offset;
+                if (loc.row != visitRow) {
+                    visitRow = loc.row;
+                    visitedRows++;
+                    if (findLarge ? edge > value : edge < value) {
+                        row = visitRow;
+                        value = edge;
+                        index = i;
+                    }
+                }
+            }
+        } else {
+            value = edge + mProvider.getSize(indexLimit);
+            for (int i = indexLimit - 1; visitedRows < mNumRows && i >= mFirstVisibleIndex; i--) {
+                edge -= loc.offset;
+                loc = getLocation(i);
+                if (loc.row != visitRow) {
+                    visitRow = loc.row;
+                    visitedRows++;
+                    int newValue = edge + mProvider.getSize(i);
+                    if (findLarge ? newValue > value : newValue < value) {
+                        row = visitRow;
+                        value = newValue;
+                        index = i;
+                    }
+                }
+            }
+        }
+        if (indices != null) {
+            indices[0] = row;
+            indices[1] = index;
+        }
+        return value;
+    }
+
+    /**
+     * Note this method has assumption that item is filled either in the same row
+     * next row of last item.  Search until row index wrapped.
+     */
+    @Override
+    public int findRowMin(boolean findLarge, int indexLimit, int[] indices) {
+        int value;
+        int edge = mProvider.getEdge(indexLimit);
+        Location loc = getLocation(indexLimit);
+        int row = loc.row;
+        int index = indexLimit;
+        int visitedRows = 1;
+        int visitRow = row;
+        if (mReversedFlow) {
+            value = edge - mProvider.getSize(indexLimit);
+            for (int i = indexLimit - 1; visitedRows < mNumRows && i >= mFirstVisibleIndex; i--) {
+                edge -= loc.offset;
+                loc = getLocation(i);
+                if (loc.row != visitRow) {
+                    visitRow = loc.row;
+                    visitedRows++;
+                    int newValue = edge - mProvider.getSize(i);
+                    if (findLarge ? newValue > value : newValue < value) {
+                        value = newValue;
+                        row = visitRow;
+                        index = i;
+                    }
+                }
+            }
+        } else {
+            value = edge;
+            for (int i = indexLimit + 1; visitedRows < mNumRows && i <= mLastVisibleIndex; i++) {
+                loc = getLocation(i);
+                edge += loc.offset;
+                if (loc.row != visitRow) {
+                    visitRow = loc.row;
+                    visitedRows++;
+                    if (findLarge ? edge > value : edge < value) {
+                        value = edge;
+                        row = visitRow;
+                        index = i;
+                    }
+                }
+            }
+        }
+        if (indices != null) {
+            indices[0] = row;
+            indices[1] = index;
+        }
+        return value;
+    }
+
+    private int findRowEdgeLimitSearchIndex(boolean append) {
+        boolean wrapped = false;
+        if (append) {
+            for (int index = mLastVisibleIndex; index >= mFirstVisibleIndex; index--) {
+                int row = getLocation(index).row;
+                if (row == 0) {
+                    wrapped = true;
+                } else if (wrapped && row == mNumRows - 1) {
+                    return index;
+                }
+            }
+        } else {
+            for (int index = mFirstVisibleIndex; index <= mLastVisibleIndex; index++) {
+                int row = getLocation(index).row;
+                if (row == mNumRows - 1) {
+                    wrapped = true;
+                } else if (wrapped && row == 0) {
+                    return index;
+                }
+            }
+        }
+        return -1;
+    }
+
+    @Override
+    protected boolean appendVisibleItemsWithoutCache(int toLimit, boolean oneColumnMode) {
+        final int count = mProvider.getCount();
+        int itemIndex;
+        int rowIndex;
+        int edgeLimit;
+        boolean edgeLimitIsValid;
+        if (mLastVisibleIndex >= 0) {
+            if (mLastVisibleIndex < getLastIndex()) {
+                // should fill using cache instead
+                return false;
+            }
+            itemIndex = mLastVisibleIndex + 1;
+            rowIndex = getLocation(mLastVisibleIndex).row;
+            // find start item index of "previous column"
+            int edgeLimitSearchIndex = findRowEdgeLimitSearchIndex(true);
+            if (edgeLimitSearchIndex < 0) {
+                // if "previous column" is not found, using edgeLimit of
+                // first row currently in grid
+                edgeLimit = Integer.MIN_VALUE;
+                for (int i = 0; i < mNumRows; i++) {
+                    edgeLimit = mReversedFlow ? getRowMin(i) : getRowMax(i);
+                    if (edgeLimit != Integer.MIN_VALUE) {
+                        break;
+                    }
+                }
+            } else {
+                edgeLimit = mReversedFlow ? findRowMin(false, edgeLimitSearchIndex, null) :
+                        findRowMax(true, edgeLimitSearchIndex, null);
+            }
+            if (mReversedFlow ? getRowMin(rowIndex) <= edgeLimit
+                    : getRowMax(rowIndex) >= edgeLimit) {
+                // if current row exceeds previous column, fill from next row
+                rowIndex = rowIndex + 1;
+                if (rowIndex == mNumRows) {
+                    // start a new column and using edge limit of current column
+                    rowIndex = 0;
+                    edgeLimit = mReversedFlow ? findRowMin(false, null) : findRowMax(true, null);
+                }
+            }
+            edgeLimitIsValid = true;
+        } else {
+            itemIndex = mStartIndex != START_DEFAULT ? mStartIndex : 0;
+            // if there are cached items,  put on next row of last cached item.
+            rowIndex = (mLocations.size() > 0 ? getLocation(getLastIndex()).row + 1 : itemIndex)
+                    % mNumRows;
+            edgeLimit = 0;
+            edgeLimitIsValid = false;
+        }
+
+        boolean filledOne = false;
+        while (true) {
+            // find end-most row edge (.high is biggest, or .low is smallest in reversed flow)
+            // fill from current row till last row so that each row will grow longer than
+            // the previous highest row.
+            for (; rowIndex < mNumRows; rowIndex++) {
+                // fill one item to a row
+                if (itemIndex == count || (!oneColumnMode && checkAppendOverLimit(toLimit))) {
+                    return filledOne;
+                }
+                int location = mReversedFlow ? getRowMin(rowIndex) : getRowMax(rowIndex);
+                if (location == Integer.MAX_VALUE || location == Integer.MIN_VALUE) {
+                    // nothing on the row
+                    if (rowIndex == 0) {
+                        location = mReversedFlow ? getRowMin(mNumRows - 1) : getRowMax(mNumRows - 1);
+                        if (location != Integer.MAX_VALUE && location != Integer.MIN_VALUE) {
+                            location = location + (mReversedFlow ? -mSpacing : mSpacing);
+                        }
+                    } else {
+                        location = mReversedFlow ? getRowMax(rowIndex - 1) : getRowMin(rowIndex - 1);
+                    }
+                } else {
+                    location = location + (mReversedFlow ? -mSpacing : mSpacing);
+                }
+                int size = appendVisibleItemToRow(itemIndex++, rowIndex, location);
+                filledOne = true;
+                // fill more item to the row to make sure this row is longer than
+                // the previous highest row.
+                if (edgeLimitIsValid) {
+                    while (mReversedFlow ? location - size > edgeLimit :
+                            location + size < edgeLimit) {
+                        if (itemIndex == count || (!oneColumnMode && checkAppendOverLimit(toLimit))) {
+                            return filledOne;
+                        }
+                        location = location + (mReversedFlow ? - size - mSpacing : size + mSpacing);
+                        size = appendVisibleItemToRow(itemIndex++, rowIndex, location);
+                    }
+                } else {
+                    edgeLimitIsValid = true;
+                    edgeLimit = mReversedFlow ? getRowMin(rowIndex) : getRowMax(rowIndex);
+                }
+            }
+            if (oneColumnMode) {
+                return filledOne;
+            }
+            edgeLimit = mReversedFlow ? findRowMin(false, null) : findRowMax(true, null);
+            // start fill from row 0 again
+            rowIndex = 0;
+        }
+    }
+
+    @Override
+    protected boolean prependVisibleItemsWithoutCache(int toLimit, boolean oneColumnMode) {
+        int itemIndex;
+        int rowIndex;
+        int edgeLimit;
+        boolean edgeLimitIsValid;
+        if (mFirstVisibleIndex >= 0) {
+            if (mFirstVisibleIndex > getFirstIndex()) {
+                // should fill using cache instead
+                return false;
+            }
+            itemIndex = mFirstVisibleIndex - 1;
+            rowIndex = getLocation(mFirstVisibleIndex).row;
+            // find start item index of "previous column"
+            int edgeLimitSearchIndex = findRowEdgeLimitSearchIndex(false);
+            if (edgeLimitSearchIndex < 0) {
+                // if "previous column" is not found, using edgeLimit of
+                // last row currently in grid and fill from upper row
+                rowIndex = rowIndex - 1;
+                edgeLimit = Integer.MAX_VALUE;
+                for (int i = mNumRows - 1; i >= 0; i--) {
+                    edgeLimit = mReversedFlow ? getRowMax(i) : getRowMin(i);
+                    if (edgeLimit != Integer.MAX_VALUE) {
+                        break;
+                    }
+                }
+            } else {
+                edgeLimit = mReversedFlow ? findRowMax(true, edgeLimitSearchIndex, null) :
+                        findRowMin(false, edgeLimitSearchIndex, null);
+            }
+            if (mReversedFlow ? getRowMax(rowIndex) >= edgeLimit
+                    : getRowMin(rowIndex) <= edgeLimit) {
+                // if current row exceeds previous column, fill from next row
+                rowIndex = rowIndex - 1;
+                if (rowIndex < 0) {
+                    // start a new column and using edge limit of current column
+                    rowIndex = mNumRows - 1;
+                    edgeLimit = mReversedFlow ? findRowMax(true, null) :
+                            findRowMin(false, null);
+                }
+            }
+            edgeLimitIsValid = true;
+        } else {
+            itemIndex = mStartIndex != START_DEFAULT ? mStartIndex : 0;
+            // if there are cached items,  put on previous row of first cached item.
+            rowIndex = (mLocations.size() > 0 ? getLocation(getFirstIndex()).row + mNumRows - 1
+                    : itemIndex) % mNumRows;
+            edgeLimit = 0;
+            edgeLimitIsValid = false;
+        }
+        boolean filledOne = false;
+        while (true) {
+            // find start-most row edge (.low is smallest, or .high is largest in reversed flow)
+            // fill from current row till first row so that each row will grow longer than
+            // the previous lowest row.
+            for (; rowIndex >= 0; rowIndex--) {
+                // fill one item to a row
+                if (itemIndex < 0 || (!oneColumnMode && checkPrependOverLimit(toLimit))) {
+                    return filledOne;
+                }
+                int location = mReversedFlow ? getRowMax(rowIndex) : getRowMin(rowIndex);
+                if (location == Integer.MAX_VALUE || location == Integer.MIN_VALUE) {
+                    // nothing on the row
+                    if (rowIndex == mNumRows - 1) {
+                        location = mReversedFlow ? getRowMax(0) : getRowMin(0);
+                        if (location != Integer.MAX_VALUE && location != Integer.MIN_VALUE) {
+                            location = location + (mReversedFlow ? mSpacing : -mSpacing);
+                        }
+                    } else {
+                        location = mReversedFlow ? getRowMin(rowIndex + 1) : getRowMax(rowIndex + 1);
+                    }
+                } else {
+                    location = location + (mReversedFlow ? mSpacing : -mSpacing);
+                }
+                int size = prependVisibleItemToRow(itemIndex--, rowIndex, location);
+                filledOne = true;
+
+                // fill more item to the row to make sure this row is longer than
+                // the previous highest row.
+                if (edgeLimitIsValid) {
+                    while (mReversedFlow ? location + size < edgeLimit :
+                            location - size > edgeLimit) {
+                        if (itemIndex < 0 || (!oneColumnMode && checkPrependOverLimit(toLimit))) {
+                            return filledOne;
+                        }
+                        location = location + (mReversedFlow ? size + mSpacing : -size - mSpacing);
+                        size = prependVisibleItemToRow(itemIndex--, rowIndex, location);
+                    }
+                } else {
+                    edgeLimitIsValid = true;
+                    edgeLimit = mReversedFlow ? getRowMax(rowIndex) : getRowMin(rowIndex);
+                }
+            }
+            if (oneColumnMode) {
+                return filledOne;
+            }
+            edgeLimit = mReversedFlow ? findRowMax(true, null) : findRowMin(false, null);
+            // start fill from last row again
+            rowIndex = mNumRows - 1;
+        }
+    }
+
+
+}
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/src/main/res/values-af/strings.xml b/leanback/src/main/res/values-af/strings.xml
new file mode 100644
index 0000000..7135f96
--- /dev/null
+++ b/leanback/src/main/res/values-af/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="8126335323963415494">"Navigasiekieslys"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Soekhandeling"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Soek"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Praat om te soek"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Deursoek <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Praat om <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> te deursoek"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Speel"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Onderbreek"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Spoel vorentoe"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Spoel vorentoe %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Spoel terug"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Spoel terug %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Slaan volgende oor"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Slaan vorige oor"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Meer handelinge"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Ontkies laaik baie"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Kies laaik baie"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Ontkies laaik niks"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Kies laaik niks"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Herhaal niks"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Herhaal alles"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Herhaal een"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Aktiveer skommel"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Deaktiveer skommel"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Aktiveer hoë gehalte"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Deaktiveer hoë gehalte"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Aktiveer onderskrifte"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Deaktiveer onderskrifte"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Voer prent in prentmodus in"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Mediakontroles word gewys"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Mediakontroles word versteek; druk D-paneel om te wys"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Voltooi"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Gaan voort"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"MediaPlayer-foutkode %1$d ekstra %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"BEGIN HIER"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Volgende"</string>
+</resources>
diff --git a/leanback/src/main/res/values-am/strings.xml b/leanback/src/main/res/values-am/strings.xml
new file mode 100644
index 0000000..79b03b5
--- /dev/null
+++ b/leanback/src/main/res/values-am/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="8126335323963415494">"የዳሰሳ ምናሌ"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"የፍለጋ እርምጃ"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"ይፈልጉ"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"ለመፈለግ ይናገሩ"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>ን ይፈልጉ"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>ን ለመፈለግ ይናገሩ"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"አጫውት"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"ለአፍታ አቁም"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"በፍጥነት አሳልፍ"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"በ%1$dX ወደፊት አፍጥን"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"አጠንጥን"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"በ%1$dX አጠንጥን"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"የሚቀጥለውን ዝለል"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"ቀዳሚውን ዝለል"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"ተጨማሪ እርምጃዎች"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"አሪፍን አትምረጥ"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"አሪፍን ምረጥ"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"ደባሪን አትምረጥ"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"ደባሪን ምረጥ"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"ምንም አትድገም"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"ሁሉንም ድገም"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"አንዱን ድገም"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"መበወዣን አንቃ"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"መበወዣን አሰናክል"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"ከፍተኛ ጥራትን አንቃ"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"ከፍተኛ ጥራትን አሰናክል"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"ዝግ የመግለጫ ጽሑፎችን አንቃ"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"ዝግ የመግለጫ ጽሑፎችን አሰናክል"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"ስዕል-በስዕል ሁነታ ውስጥ ይግቡ"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"የሚዲያ መቆጣጠሪያዎች እንዲታዩ ተደርገዋል"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"የሚዲያ መቆጣጠሪያዎች ተደብቀዋል፣ ለማሳየት d-pad ን ይጫኑ"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"ጨርስ"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"ቀጥል"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"የMediaPlayer ስህተት ኮድ %1$d ተጨማሪ %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"ጀምር"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"ቀጣይ"</string>
+</resources>
diff --git a/leanback/src/main/res/values-ar/strings.xml b/leanback/src/main/res/values-ar/strings.xml
new file mode 100644
index 0000000..5b4dbf4
--- /dev/null
+++ b/leanback/src/main/res/values-ar/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="8126335323963415494">"قائمة التنقل"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"إجراء البحث"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"البحث"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"تحدَّثْ لبدء البحث"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"بحث في <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"تحدَّثْ لبدء البحث في <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"تشغيل"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"إيقاف مؤقت"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"تقديم سريع"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"‏التقديم السريع بمقدار %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"إرجاع"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"‏إرجاع بمقدار %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"تخطي التالي"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"تخطي السابق"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"مزيد من الإجراءات"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"إلغاء اختيار التقييم \"أعجبني\""</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"اختيار التقييم \"أعجبني\""</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"إلغاء اختيار التقييم \"لا يعجبني\""</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"اختيار التقييم \"لا يعجبني\""</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"عدم التكرار"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"تكرار الكل"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"تكرار مقطع واحد"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"تفعيل الترتيب العشوائي"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"إيقاف الترتيب العشوائي"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"تفعيل الجودة العالية"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"إيقاف الجودة العالية"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"تفعيل الترجمة والشرح"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"إيقاف الترجمة والشرح"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"الدخول في الوضع \"نافذة ضمن النافذة\""</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"تم إظهار عناصر التحكم في الوسائط"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"تم إخفاء عناصر التحكم في الوسائط، ويمكنك الضغط على لوحة التحكم لإظهارها"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"إنهاء"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"متابعة"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"‏رمز الخطأ %1$d في MediaPlayer بالإضافة إلى %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"البدء"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"التالي"</string>
+</resources>
diff --git a/leanback/src/main/res/values-az/strings.xml b/leanback/src/main/res/values-az/strings.xml
new file mode 100644
index 0000000..14596a1
--- /dev/null
+++ b/leanback/src/main/res/values-az/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="8126335323963415494">"Naviqasiya menyusu"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Axtarış Əməliyyatı"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Axtarın"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Axtarış üçün danışın"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Axtarın: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Axtarış üçün danışın: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Fasilə verin"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Dayandırın"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Sürətli Yönləndirmə"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Sürətli Yönləndirmə %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Geri çəkin"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Geri çəkin %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Növbətini Keçin"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Öncəkini Keçin"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Digər Əməliyyatlar"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Bəyənməkdən imtina edin"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Bəyənin"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Bəyənməməkdən İmtina Edin"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Bəyənməyin"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Təkrarlanmasın"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Hamısını Təkrarlayın"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Biri təkrarlansın"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Qarışdırmanı Aktiv edin"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Qarışdırmanı Deaktiv edin"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Yüksək Keyfiyyəti Aktiv edin"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Yüksək Keyfiyyəti Deaktiv edin"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Qapalı Çəkilişi Aktiv edin"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Qapalı Çəkilişi Deaktiv edin"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Şəkil içində Şəkil Rejiminə daxil olun"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Media nəzarətləri açıqdır"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Media idarəetmələri gizlidir, göstərmək üçün d-pad\'i basın"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Tamamlayın"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Davam edin"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"Media Pleyer xəta kodu %1$d əlavə %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"BAŞLAYIN"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Sonrakı"</string>
+</resources>
diff --git a/leanback/src/main/res/values-b+sr+Latn/strings.xml b/leanback/src/main/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..7b86cc5
--- /dev/null
+++ b/leanback/src/main/res/values-b+sr+Latn/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="8126335323963415494">"Meni za navigaciju"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Radnja pretrage"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Pretražite"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Izgovorite da biste pretraživali"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Pretražite <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Izgovorite da biste pretražili <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Pusti"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Pauziraj"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Premotaj unapred"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Premotaj unapred %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Premotaj unazad"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Premotaj unazad %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Preskoči na sledeće"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Preskoči na prethodno"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Još radnji"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Opozovi izbor „Sviđa mi se“"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Izaberi „Sviđa mi se“"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Opozovi izbor „Ne sviđa mi se“"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Izaberi „Ne sviđa mi se“"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Ne ponavljaj nijednu"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Ponovi sve"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Ponovi jednu"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Omogući nasumično puštanje"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Onemogući nasumično puštanje"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Omogući visok kvalitet"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Onemogući visok kvalitet"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Omogući titlove"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Onemogući titlove"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Uđi u režim Slika u slici"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Kontrole za medije su prikazane"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Kontrole za medije su skrivene, pritisnite d-pad da biste ih prikazali"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Završi"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Nastavi"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"Kôd greške MediaPlayer-a: %1$d, dodatno %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"ZAPOČNITE"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Dalje"</string>
+</resources>
diff --git a/leanback/src/main/res/values-be/strings.xml b/leanback/src/main/res/values-be/strings.xml
new file mode 100644
index 0000000..2828004
--- /dev/null
+++ b/leanback/src/main/res/values-be/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="8126335323963415494">"Меню навігацыі"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Пошук"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Пошук"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Прамоўце пошукавы запыт"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Шукаць тут <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Прамоўце пошукавы запыт тут <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Прайграць"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Паўза"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Перамотка ўперад"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Перамотка ўперад %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Пераматаць"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Перамотка назад %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Перайсці да наступнага элемента"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Перайсці да папярэдняга элемента"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Іншыя дзеянні"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Зняць адзнаку \"Падабаецца\""</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Паставіць адзнаку \"Падабаецца\""</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Зняць адзнаку \"Не падабаецца\""</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Паставіць адзнаку \"Не падабаецца\""</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Не паўтараць нічога"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Паўтарыць усе"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Паўтарыць адзін элемент"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Уключыць перамешванне"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Адключыць перамешванне"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Уключыць высокую якасць"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Адключыць высокую якасць"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Уключыць схаваныя цітры"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Адключыць схаваныя цітры"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Увайсці ў рэжым \"Відарыс у відарысе\""</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Элементы кіравання мультымедыя паказаны"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Элементы кіравання мультымедыя схаваны. Каб паказаць іх, націсніце d-pad"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Завяршыць"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Працягнуць"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"Код памылкі MediaPlayer %1$d дадаткова %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"ПАЧАЦЬ"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Далей"</string>
+</resources>
diff --git a/leanback/src/main/res/values-bg/strings.xml b/leanback/src/main/res/values-bg/strings.xml
new file mode 100644
index 0000000..0eacf0d
--- /dev/null
+++ b/leanback/src/main/res/values-bg/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="8126335323963415494">"Меню за навигация"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Действие за търсене"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Търсете"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Търсете с глас"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Търсете в/ъв <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Търсете с глас в/ъв <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Възпроизвеждане"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Поставяне на пауза"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Превъртане напред"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Превъртане напред със скорост %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Превъртане назад"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Превъртане назад със скорост %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Към следващия елемент"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Към предишния елемент"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Още действия"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Отмяна на „Харесва ми“"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Избиране на „Харесва ми“"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Отмяна на „Не ми харесва“"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Избиране на „Не ми харесва“"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Без повтаряне"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Повтаряне на всички"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Повтаряне на един елемент"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Активиране на разбъркването"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Деактивиране на разбъркването"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Активиране на високото качество"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Деактивиране на високото качество"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Активиране на субтитрите"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Деактивиране на субтитрите"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Преминаване в режим „Картина в картината“"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Контролите за мултимедия са показани"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Контролите за мултимедия са скрити. Натиснете контролния пад, за да се покажат"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Край"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Напред"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"Код на грешката на MediaPlayer %1$d (допълнително: %2$d)"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"ПЪРВИ СТЪПКИ"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Напред"</string>
+</resources>
diff --git a/leanback/src/main/res/values-bn/strings.xml b/leanback/src/main/res/values-bn/strings.xml
new file mode 100644
index 0000000..c7c7bed
--- /dev/null
+++ b/leanback/src/main/res/values-bn/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="8126335323963415494">"নেভিগেশন মেনু"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"খোঁজার কার্যকলাপ"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"সার্চ"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"বলার মাধ্যমে খুঁজুন"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> খুঁজুন"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> বলে সেটি খুঁজুন"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"চালান"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"পজ করুন"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"ফাস্ট ফরওয়ার্ড"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"%1$dX স্পিডে ফাস্ট ফরওয়ার্ড করুন"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"পিছিয়ে যান"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"%1$dX স্পিডে পিছিয়ে যান"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"সরাসরি পরেরটিতে চলে যান"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"সরাসরি আগেরটিতে চলে যান"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"আরও কার্যকলাপ"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"উপরের দিকে করা বুড়ো আঙ্গুলের চিহ্নকে বাদ দিন"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"উপরের দিকে করা বুড়ো আঙ্গুলের চিহ্নকে বেছে নিন"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"নিচের দিকে করা বুড়ো আঙ্গুলের চিহ্নকে বাদ দিন"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"নিচের দিকে করা বুড়ো আঙ্গুলের চিহ্নকে বেছে নিন"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"কোনও আইটেম আবার চালাবেন না"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"সবগুলি আইটেম আবার চালান"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"একটি আইটেম আবার চালান"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"শাফেল চালু করুন"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"শাফেল বন্ধ করুন"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"খুব ভাল কোয়ালিটি চালু করুন"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"খুব ভাল কোয়ালিটি বন্ধ করুন"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"সাবটাইটেল চালু করুন"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"সাবটাইটেল বন্ধ করুন"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"\'ছবির মধ্যে ছবি\' মোডে যান"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"মিডিয়ার নিয়ন্ত্রণগুলি দেখানো হয়েছে"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"মিডিয়ার নিয়ন্ত্রণগুলি লুকানো আছে, দেখার জন্য ডি-প্যাড টিপুন"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"শেষ করুন"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"এগিয়ে যান"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"MediaPlayer সমস্যা কোড %1$d অতিরিক্ত %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"শুরু করা যাক"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"পরবর্তী"</string>
+</resources>
diff --git a/leanback/src/main/res/values-bs/strings.xml b/leanback/src/main/res/values-bs/strings.xml
new file mode 100644
index 0000000..33111a1
--- /dev/null
+++ b/leanback/src/main/res/values-bs/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="8126335323963415494">"Meni za navigaciju"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Pretraživanje"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Traži"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Kažite nešto da pokrenete pretragu"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Pretraži <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Kažite nešto da pokrenete pretragu <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Reproduciraj"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Pauza"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Ubrzaj"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Ubrzaj %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Premotavanje unazad"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Premotaj %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Preskoči sljedeće"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Preskoči prethodno"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Više radnji"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Poništi pozitivnu ocjenu"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Odaberi pozitivnu ocjenu"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Poništi negativnu ocjenu"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Odaberi negativnu ocjenu"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Ne ponavljaj"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Ponovi sve"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Ponovi jedno"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Uključi nasumičnu reprodukciju"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Isključi nasumičnu reprodukciju"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Uključi visoki kvalitet"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Isključi visoki kvalitet"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Uključi titlove"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Isključi titlove"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Uđi u način rada Slika u slici"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Kontrole za medije su prikazane"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Kontrole za medije su skrivene. Pritisnite d-pad da ih prikažete"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Završi"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Nastavi"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"Kôd greške MediaPlayera %1$d dodatno %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"ZAPOČNI"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Dalje"</string>
+</resources>
diff --git a/leanback/src/main/res/values-ca/strings.xml b/leanback/src/main/res/values-ca/strings.xml
new file mode 100644
index 0000000..3a2b592
--- /dev/null
+++ b/leanback/src/main/res/values-ca/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="8126335323963415494">"Menú de navegació"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Acció de cerca"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Cerca"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Parla per cercar"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Cerca a <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Parla per cercar a <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Reprodueix"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Posa en pausa"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Avança ràpidament"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Avança ràpidament %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Rebobina"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Rebobina %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Passa al següent"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Passa a l\'anterior"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Més accions"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Desselecciona \"M\'agrada\""</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Selecciona \"M\'agrada\""</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Desselecciona \"No m\'agrada\""</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Selecciona \"No m\'agrada\""</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"No en repeteixis cap"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Repeteix-ho tot"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Repeteix un element"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Activa la reproducció aleatòria"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Desactiva la reproducció aleatòria"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Activa l\'alta qualitat"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Desactiva l\'alta qualitat"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Activa els subtítols"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Desactiva els subtítols"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Entra al mode de pantalla en pantalla"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Es mostren els controls multimèdia"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"S\'han amagat els controls multimèdia; prem la creu direccional per mostrar-los"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Finalitza"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Continua"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"Codi d\'error de MediaPlayer %1$d extra %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"COMENÇA"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Següent"</string>
+</resources>
diff --git a/leanback/src/main/res/values-cs/strings.xml b/leanback/src/main/res/values-cs/strings.xml
new file mode 100644
index 0000000..3b3baa8
--- /dev/null
+++ b/leanback/src/main/res/values-cs/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="8126335323963415494">"Navigační nabídka"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Akce vyhledávání"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Hledat"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Vyhledávejte hlasem"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Hledat <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Vyhledávejte v kontextu <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> hlasem"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$d×"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$d×"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Přehrát"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Pozastavit"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Přetočit vpřed"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Přetočit vpřed %1$d×"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Přetočit zpět"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Přetočit zpět %1$d×"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Přeskočit na další"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Přeskočit na předchozí"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Další akce"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Zrušit výběr hodnocení palec nahoru"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Vybrat hodnocení palec nahoru"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Zrušit výběr hodnocení palec dolů"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Vybrat hodnocení palec dolů"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Neopakovat"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Opakovat vše"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Opakovat jednu položku"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Zapnout náhodné přehrávání"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Vypnout náhodné přehrávání"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Zapnout vysokou kvalitu"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Vypnout vysokou kvalitu"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Zapnout titulky"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Vypnout titulky"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Přejít do režimu obraz v obraze"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Ovládací prvky médií jsou zobrazeny"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Ovládací prvky médií jsou skryty, zobrazíte je stisknutím křížového ovladače"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Dokončit"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Pokračovat"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"Kód chyby přehrávače MediaPlayer %1$d, další %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"ZAČÍT"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Další"</string>
+</resources>
diff --git a/leanback/src/main/res/values-da/strings.xml b/leanback/src/main/res/values-da/strings.xml
new file mode 100644
index 0000000..dfca79d
--- /dev/null
+++ b/leanback/src/main/res/values-da/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="8126335323963415494">"Navigationsmenu"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Søg handling"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Søg"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Tal for at søge"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Søg efter <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Tal for at søge efter <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Afspil"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Sæt på pause"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Spol frem"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Spol frem %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Spol tilbage"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Spol tilbage %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Spring til næste"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Spring til forrige"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Flere handlinger"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Fravælg tommelfinger op"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Vælg tommelfinger op"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Fravælg tommelfinger ned"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Vælg tommelfinger ned"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Gentag ingen"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Gentag alle"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Gentag én"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Slå bland til"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Slå bland fra"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Slå høj kvalitet til"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Slå høj kvalitet fra"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Slå undertekster til"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Slå undertekster fra"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Tilstand med integreret billede"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Knapperne til afspilning er synlige"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Knapperne til afspilning er skjult. Tryk på D-pad\'en for at se dem"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Afslut"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Fortsæt"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"MediaPlayer-fejlkode %1$d ekstra %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"KOM GODT I GANG"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Næste"</string>
+</resources>
diff --git a/leanback/src/main/res/values-de/strings.xml b/leanback/src/main/res/values-de/strings.xml
new file mode 100644
index 0000000..a9bfe23
--- /dev/null
+++ b/leanback/src/main/res/values-de/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="8126335323963415494">"Navigationsmenü"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Suchvorgang"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Suche"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Zum Suchen sprechen"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"In <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> suchen"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Zum Suchen in <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> sprechen"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Wiedergeben"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Pausieren"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Vorspulen"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Vorspulen %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Zurückspulen"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Zurückspulen %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Nächstes Element überspringen"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Vorheriges Element überspringen"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Weitere Aktionen"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"\"Mag ich\" deaktivieren"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"\"Mag ich\" aktivieren"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"\"Mag ich nicht\" deaktivieren"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"\"Mag ich nicht\" aktivieren"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Kein Element wiederholen"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Alle wiederholen"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Ein Element wiederholen"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Zufallsmix aktivieren"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Zufallsmix deaktivieren"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Hohe Qualität aktivieren"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Hohe Qualität deaktivieren"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Untertitel aktivieren"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Untertitel deaktivieren"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Bild-im-Bild-Modus aktivieren"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Mediensteuerelemente eingeblendet"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Mediensteuerelemente ausgeblendet. Drücke das Steuerkreuz, um die Steuerelemente wieder einzublenden"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Fertig"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Weiter"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"MediaPlayer-Fehlercode %1$d extra %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"JETZT STARTEN"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Weiter"</string>
+</resources>
diff --git a/leanback/src/main/res/values-el/strings.xml b/leanback/src/main/res/values-el/strings.xml
new file mode 100644
index 0000000..27503c5
--- /dev/null
+++ b/leanback/src/main/res/values-el/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="8126335323963415494">"Μενού πλοήγησης"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Ενέργεια αναζήτησης"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Αναζήτηση"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Μιλήστε για να κάνετε αναζήτηση"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Αναζήτηση <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Μιλήστε για να κάνετε αναζήτηση σε <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Αναπαραγωγή"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Παύση"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Γρήγορη προώθηση"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Γρήγορη προώθηση %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Επαναφορά"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Επαναφορά %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Παράβλεψη επόμενου"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Παράβλεψη προηγούμενου"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Περισσότερες ενέργειες"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Αποεπιλογή αξιολόγησης \"Μου αρέσουν\""</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Επιλογή αξιολόγησης \"Μου αρέσουν\""</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Αποεπιλογή αξιολόγησης \"Δεν εγκρίνω\""</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Επιλογή αξιολόγησης \"Δεν εγκρίνω\""</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Καμία επανάληψη"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Επανάληψη όλων"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Επανάληψη ενός στοιχείου"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Ενεργοποίηση τυχαίας αναπαραγωγής"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Απενεργοποίηση τυχαίας αναπαραγωγής"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Ενεργοποίηση υψηλής ποιότητας"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Απενεργοποίηση υψηλής ποιότητας"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Ενεργοποίηση υποτίτλων"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Απενεργοποίηση υποτίτλων"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Εισαγωγή εικόνας στη λειτουργία παράθεσης εικόνων"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Εμφάνιση στοιχείων ελέγχου μέσων"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Απόκρυψη στοιχείων ελέγχου μέσων, πιέστε το d-pad για εμφάνιση"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Τέλος"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Συνέχεια"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"Κωδικός σφάλματος MediaPlayer %1$d επιπλέον %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"ΕΝΑΡΞΗ"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Επόμενη"</string>
+</resources>
diff --git a/leanback/src/main/res/values-en-rAU/strings.xml b/leanback/src/main/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000..6f79fd1
--- /dev/null
+++ b/leanback/src/main/res/values-en-rAU/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="8126335323963415494">"Navigation menu"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Search Action"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Search"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Speak to search"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Search <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Speak to search <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Play"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Pause"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Fast Forward"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Fast Forward %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Rewind"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Rewind %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Skip Next"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Skip Previous"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"More Actions"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Deselect Thumb Up"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Select Thumb Up"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Deselect Thumb Down"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Select Thumb Down"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Repeat None"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Repeat All"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Repeat One"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Enable Shuffle"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Disable Shuffle"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Enable High Quality"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Disable High Quality"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Enable Closed Captioning"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Disable Closed Captioning"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Enter Picture In Picture Mode"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Media controls shown"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Media controls hidden, press d-pad to show"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Finish"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Continue"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"MediaPlayer error code %1$d extra %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"GET STARTED"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Next"</string>
+</resources>
diff --git a/leanback/src/main/res/values-en-rCA/strings.xml b/leanback/src/main/res/values-en-rCA/strings.xml
new file mode 100644
index 0000000..6f79fd1
--- /dev/null
+++ b/leanback/src/main/res/values-en-rCA/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="8126335323963415494">"Navigation menu"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Search Action"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Search"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Speak to search"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Search <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Speak to search <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Play"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Pause"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Fast Forward"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Fast Forward %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Rewind"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Rewind %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Skip Next"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Skip Previous"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"More Actions"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Deselect Thumb Up"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Select Thumb Up"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Deselect Thumb Down"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Select Thumb Down"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Repeat None"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Repeat All"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Repeat One"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Enable Shuffle"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Disable Shuffle"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Enable High Quality"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Disable High Quality"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Enable Closed Captioning"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Disable Closed Captioning"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Enter Picture In Picture Mode"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Media controls shown"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Media controls hidden, press d-pad to show"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Finish"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Continue"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"MediaPlayer error code %1$d extra %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"GET STARTED"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Next"</string>
+</resources>
diff --git a/leanback/src/main/res/values-en-rGB/strings.xml b/leanback/src/main/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..6f79fd1
--- /dev/null
+++ b/leanback/src/main/res/values-en-rGB/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="8126335323963415494">"Navigation menu"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Search Action"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Search"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Speak to search"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Search <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Speak to search <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Play"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Pause"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Fast Forward"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Fast Forward %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Rewind"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Rewind %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Skip Next"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Skip Previous"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"More Actions"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Deselect Thumb Up"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Select Thumb Up"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Deselect Thumb Down"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Select Thumb Down"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Repeat None"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Repeat All"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Repeat One"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Enable Shuffle"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Disable Shuffle"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Enable High Quality"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Disable High Quality"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Enable Closed Captioning"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Disable Closed Captioning"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Enter Picture In Picture Mode"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Media controls shown"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Media controls hidden, press d-pad to show"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Finish"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Continue"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"MediaPlayer error code %1$d extra %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"GET STARTED"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Next"</string>
+</resources>
diff --git a/leanback/src/main/res/values-en-rIN/strings.xml b/leanback/src/main/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..6f79fd1
--- /dev/null
+++ b/leanback/src/main/res/values-en-rIN/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="8126335323963415494">"Navigation menu"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Search Action"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Search"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Speak to search"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Search <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Speak to search <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Play"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Pause"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Fast Forward"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Fast Forward %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Rewind"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Rewind %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Skip Next"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Skip Previous"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"More Actions"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Deselect Thumb Up"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Select Thumb Up"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Deselect Thumb Down"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Select Thumb Down"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Repeat None"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Repeat All"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Repeat One"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Enable Shuffle"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Disable Shuffle"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Enable High Quality"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Disable High Quality"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Enable Closed Captioning"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Disable Closed Captioning"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Enter Picture In Picture Mode"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Media controls shown"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Media controls hidden, press d-pad to show"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Finish"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Continue"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"MediaPlayer error code %1$d extra %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"GET STARTED"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Next"</string>
+</resources>
diff --git a/leanback/src/main/res/values-en-rXC/strings.xml b/leanback/src/main/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000..39f711c
--- /dev/null
+++ b/leanback/src/main/res/values-en-rXC/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="8126335323963415494">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‎‎‏‏‎‏‎‎‎‏‎‏‎‏‏‏‎‏‏‎‎‎‎‎‎‎‏‏‎‏‎‎‎‏‏‎‎‎‏‎‏‏‎‏‏‏‏‎‎‎‏‏‎‎Navigation menu‎‏‎‎‏‎"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‎‏‎‎‎‏‎‎‏‎‎‏‎‎‎‏‎‎‎‎‏‏‎‏‏‎‎‏‏‎‎‎‎‏‏‏‎‏‏‎‏‎‎‎‎‎‏‏‏‏‎‎‎‎‎Search Action‎‏‎‎‏‎"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‎‎‎‎‏‎‏‏‏‎‏‎‏‎‎‎‎‏‏‎‎‏‎‏‏‎‎‎‏‎‏‎‎‏‎‎‏‎‏‏‎‎‏‎‏‎Search‎‏‎‎‏‎"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‎‏‏‎‎‏‎‏‏‏‎‎‎‎‏‎‏‎‏‏‎‎‏‏‏‏‎‎‎‏‏‎‏‎‎‏‏‏‎‎‏‎‎‎‎‎‏‎‎‎‎‏‎‎‏‏‎‎Speak to search‎‏‎‎‏‎"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‏‏‎‎‎‏‎‎‎‎‎‏‎‏‎‏‏‏‎‏‏‏‏‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‏‎‏‏‏‏‏‎‏‎‏‏‏‏‏‏‎Search ‎‏‎‎‏‏‎<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‎‏‏‎‏‎‏‎‏‏‎‎‏‎‎‏‏‎‎‎‏‏‎‏‎‏‎‎‎‏‏‏‏‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‏‎‏‎‎‏‎Speak to search ‎‏‎‎‏‏‎<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‏‏‎‎‎‏‎‏‏‏‎‏‏‏‎‏‏‏‎‎‎‎‏‎‏‏‏‎‎‎‏‏‏‎‎‏‏‏‏‏‏‎‏‎‏‏‏‏‎‏‎‏‏‎‎‎‎%1$dX‎‏‎‎‏‎"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‎‏‏‎‏‏‎‎‏‎‏‎‎‎‏‎‏‏‏‏‏‏‎‎‏‎‏‎‎‎‏‏‏‏‎‏‎‎‎‎‎‏‏‏‏‎‏‎‏‎‏‏‏‎%1$dX‎‏‎‎‏‎"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‎‎‎‎‏‎‎‏‎‎‎‏‎‎‎‎‎‏‏‎‏‏‏‏‏‎‎‎‏‎‎‎‏‏‎‏‏‏‏‎‏‎‎‎‏‎‎‎‎‎‏‎‏‏‎‏‎‎Play‎‏‎‎‏‎"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‏‎‎‎‏‏‎‏‎‎‏‏‎‏‏‏‏‎‎‎‏‏‏‏‎‎‏‎‏‏‏‏‎‏‏‏‎‏‏‎‎‏‏‏‏‏‎‏‎‏‎‎‎‎‎‏‎Pause‎‏‎‎‏‎"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‎‎‎‎‏‎‏‏‏‎‏‏‎‏‎‏‎‏‎‏‎‏‎‏‏‎‎‏‏‏‎‎‏‏‎‏‎‎‎‎‏‎‎‎‎‏‏‏‎‎‎‎Fast Forward‎‏‎‎‏‎"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‏‎‎‎‏‏‏‏‎‏‎‏‏‎‏‎‎‎‏‏‏‎‎‎‎‎‎‏‏‏‎‏‏‎‎‎‏‏‎‎‎‏‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎Fast Forward %1$dX‎‏‎‎‏‎"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‏‏‎‎‏‏‎‏‎‏‏‎‎‏‎‏‎‏‏‎‎‎‏‏‏‏‎‎‏‏‎‎‏‏‎‎‏‎‎‏‎‎‎‏‏‎‎‏‎‏‏‎‎‏‏‏‎‎Rewind‎‏‎‎‏‎"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‎‎‎‎‏‎‏‏‎‏‎‎‎‎‎‎‎‎‏‎‏‎‏‎‏‎‎‏‏‏‏‏‎‏‎‏‎‏‏‏‎‏‎‎‏‎‏‎‏‏‎‏‎Rewind %1$dX‎‏‎‎‏‎"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‏‎‏‏‏‎‏‎‎‏‏‏‏‎‎‏‎‎‏‎‏‏‏‎‏‏‎‎‏‎‏‏‎‎‎‏‎‏‎‎‎‎‎‎‎‏‎‎‏‎‏‎‏‏‎Skip Next‎‏‎‎‏‎"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‏‎‏‎‏‏‎‎‏‏‎‏‎‏‎‎‏‏‎‏‏‏‎‏‏‏‏‎‏‏‏‎‏‏‏‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‏‎‏‏‎‎‎Skip Previous‎‏‎‎‏‎"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‏‎‎‏‏‏‏‏‎‏‎‏‎‏‎‎‎‏‏‏‎‎‏‏‏‏‏‎‎‏‎‎‏‏‎‏‏‎‏‏‏‎‏‏‏‎‎‏‎‏‎‏‏‏‏‎‏‎More Actions‎‏‎‎‏‎"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‎‎‏‎‎‎‎‎‏‏‏‎‎‎‏‏‏‏‎‏‎‏‏‎‎‏‎‏‏‎‎‎‏‎‏‎‎‏‏‏‏‎‎‏‏‎‎‏‏‎‏‎‎‎Deselect Thumb Up‎‏‎‎‏‎"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‎‏‏‎‏‎‎‎‏‏‏‏‎‎‎‎‏‏‏‎‎‎‎‎‎‎‏‎‏‏‎‏‎‏‏‎‏‏‎‎‏‎‏‎‎‎‏‏‎‏‎‎‎‎‎‎‎Select Thumb Up‎‏‎‎‏‎"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‏‏‎‎‎‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‎‎‎‎‎‎‎‎‏‏‎‎‏‎‏‎‎‎‎‎‎‎‏‏‎‎‏‏‎‎‏‏‏‎‎Deselect Thumb Down‎‏‎‎‏‎"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‏‏‎‎‎‎‎‏‏‏‎‏‎‏‏‎‎‏‏‎‏‏‎‎‎‏‎‎‎‏‎‎‏‎‎‏‎‏‎‏‎‏‎‏‎‏‏‎‏‏‏‏‎‎‏‏‎‎Select Thumb Down‎‏‎‎‏‎"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎‏‎‏‎‎‏‏‎‎‏‎‏‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‏‎‏‎‏‏‎‎‎‎‏‎‎‏‏‎‎‏‎‏‎‎‎‎‏‏‎Repeat None‎‏‎‎‏‎"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‏‏‎‏‎‏‏‎‏‎‎‏‎‎‏‏‎‎‏‎‎‎‏‏‏‏‎‎‎‎‏‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‏‎‎‏‎‏‎‏‎Repeat All‎‏‎‎‏‎"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‎‎‎‏‏‎‏‏‎‏‏‎‎‎‏‏‏‏‏‏‎‎‎‏‏‎‎‏‎‏‏‏‏‎‏‏‎‎‏‎‏‎‎‎‎‎‎‏‏‎‎‎‎‎Repeat One‎‏‎‎‏‎"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‎‏‏‏‏‏‎‏‏‏‎‏‎‏‎‏‎‎‏‏‎‏‏‏‎‏‎‎‏‎‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‎‏‏‏‎Enable Shuffle‎‏‎‎‏‎"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‎‏‏‎‏‏‏‎‏‏‎‎‏‏‏‎‎‎‏‎‎‎‏‏‏‏‏‎‏‏‎‏‏‏‎‏‏‎‏‎‎‏‏‏‎‎‎‏‎‎‏‏‎‎Disable Shuffle‎‏‎‎‏‎"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‏‏‏‎‏‏‎‎‏‏‎‎‎‎‏‏‏‏‎‏‏‎‏‏‏‎‏‎‏‎‏‎‎‎‎‏‏‎‏‎‏‎‏‏‎‏‎‏‏‎‎‎‎‏‏‏‎‎Enable High Quality‎‏‎‎‏‎"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎‏‎‎‎‏‎‎‏‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‎‎‎‏‎‏‏‎‎‎‎‎‎‏‏‏‏‎‎‏‎‎‎‎‏‏‎‏‏‎Disable High Quality‎‏‎‎‏‎"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‎‏‎‎‏‏‎‎‏‏‏‎‎‎‏‎‎‏‏‎‎‏‏‏‎‎‏‏‎‎‎‏‎‏‎‏‎‏‎‎‎‎‎‎‎‏‏‏‏‎‏‏‏‏‎‏‏‎Enable Closed Captioning‎‏‎‎‏‎"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‎‎‏‏‏‎‎‎‏‎‏‎‏‎‎‎‎‎‎‏‎‎‏‎‏‏‎‎‎‎‏‎‏‎‏‎‏‎‏‎‏‏‏‎‏‏‏‏‏‎‏‏‏‎‎‏‎‎Disable Closed Captioning‎‏‎‎‏‎"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‎‎‎‎‏‏‏‏‎‏‏‎‏‏‏‏‎‎‏‎‏‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‏‎‏‎‏‎‎‏‏‏‎‏‏‎Enter Picture In Picture Mode‎‏‎‎‏‎"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‏‏‎‎‏‎‎‏‎‏‎‏‎‎‎‎‎‏‎‎‏‎‏‏‎‏‏‏‎‎‏‏‎‎‎‏‎‎‏‎‎‏‏‏‎‏‏‎‏‎‎‎‏‏‏‎/‎‏‎‎‏‎"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‎‏‏‏‏‏‎‏‎‏‎‎‏‎‎‎‏‏‏‏‏‏‏‎‏‏‎‎‎‏‎‏‏‏‎‏‏‎‏‎‎‎‎Media controls shown‎‏‎‎‏‎"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‏‎‎‏‏‎‎‎‏‎‎‎‏‎‎‏‏‎‏‎‎‏‏‏‎‎‏‎‏‎‏‎‎‏‎‎‎‏‏‏‎‏‎‏‏‏‎‎‏‎‎‎‎‏‎‏‎Media controls hidden, press d-pad to show‎‏‎‎‏‎"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‎‎‎‏‏‎‎‎‎‏‏‏‏‎‏‎‏‎‏‏‎‎‎‏‎‎‏‎‏‏‎‏‏‏‏‏‎‎‏‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‎Finish‎‏‎‎‏‎"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‏‎‎‏‎‎‏‏‎‎‎‏‏‏‎‎‎‏‎‎‎‏‏‏‏‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‎‎‎‎‎‎‎‎‏‎‏‎‏‎Continue‎‏‎‎‏‎"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‏‎‎‏‎‏‏‎‏‏‏‏‎‎‏‎‏‏‏‏‎‏‏‏‏‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‎‎‏‏‎‎‏‏‎‏‎‎‎MediaPlayer error code %1$d extra %2$d‎‏‎‎‏‎"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‎‎‎‎‏‎‏‎‎‎‎‏‎‎‎‎‎‎‏‎‎‏‏‏‏‎‎‏‎‎‏‏‎‏‎‎‎‏‏‎‎‏‎‎‎‎‎‏‎‎‏‎‎‎GET STARTED‎‏‎‎‏‎"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‎‎‏‏‏‏‎‎‏‏‏‎‎‎‎‎‏‎‏‏‏‎‎‏‏‎‏‎‎‎‏‎‎‎‏‏‏‏‎‏‎‎‏‎‏‎‏‎‏‏‏‏‏‎‎‏‏‎Next‎‏‎‎‏‎"</string>
+</resources>
diff --git a/leanback/src/main/res/values-es-rUS/strings.xml b/leanback/src/main/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..340d9f5
--- /dev/null
+++ b/leanback/src/main/res/values-es-rUS/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="8126335323963415494">"Menú de navegación"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Acción de búsqueda"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Buscar"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Habla para buscar"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Busca <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Habla para buscar <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Reproducir"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Pausar"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Adelantar"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Adelantar %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Retroceder"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Retroceder %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Ir al siguiente"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Ir al anterior"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Más acciones"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Anular selección de Me gusta"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Seleccionar Me gusta"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Anular selección de No me gusta"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Seleccionar No me gusta"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"No repetir"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Repetir todo"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Repetir uno"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Habilitar reproducción aleatoria"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Inhabilitar reproducción aleatoria"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Habilitar alta calidad"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Inhabilitar alta calidad"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Habilitar subtítulos opcionales"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Inhabilitar subtítulos opcionales"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Activar el modo de pantalla en pantalla"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Se muestran los controles de contenido multimedia"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Los controles de contenido multimedia están ocultos; presiona el pad direccional para mostrarlos"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Finalizar"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Continuar"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"Código de error de MediaPlayer %1$d extra %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"COMENZAR"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Siguiente"</string>
+</resources>
diff --git a/leanback/src/main/res/values-es/strings.xml b/leanback/src/main/res/values-es/strings.xml
new file mode 100644
index 0000000..dc33a6b
--- /dev/null
+++ b/leanback/src/main/res/values-es/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="8126335323963415494">"Menú de navegación"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Buscar acción"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Haz una búsqueda"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Habla para buscar"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Busca <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Busca <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> por voz"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dx"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dx"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Reproducir"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Pausar"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Avanzar rápidamente"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Avanzar rápidamente %1$dx"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Rebobinar"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Rebobinar %1$dx"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Saltar siguiente"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Saltar anterior"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Más acciones"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"No seleccionar Me gusta"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Seleccionar Me gusta"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"No seleccionar No me gusta"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Seleccionar No me gusta"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"No repetir"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Repetir todo"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Repetir uno"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Habilitar reproducir aleatoriamente"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Inhabilitar reproducir aleatoriamente"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Habilitar alta calidad"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Inhabilitar alta calidad"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Habilitar subtítulos"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Inhabilitar subtítulos"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Activar modo pantalla en pantalla"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Controles multimedia mostrados"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Controles multimedia ocultos (pulsa la cruceta para mostrarlos)"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Finalizar"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Continuar"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"Código de error de MediaPlayer %1$d extra %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"EMPEZAR"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Siguiente"</string>
+</resources>
diff --git a/leanback/src/main/res/values-et/strings.xml b/leanback/src/main/res/values-et/strings.xml
new file mode 100644
index 0000000..24a8a9a
--- /dev/null
+++ b/leanback/src/main/res/values-et/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="8126335323963415494">"Navigeerimismenüü"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Otsimistoiming"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Otsige"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Rääkige otsimiseks"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Otsige rakendusest <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Rääkige rakendusest <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> otsimiseks"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Esita"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Peata"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Keri edasi"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Keri edasi %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Keri tagasi"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Keri tagasi %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Liigu järgmise üksuse juurde"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Liigu eelmise üksuse juurde"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Rohkem toiminguid"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Tühista valik Meeldib"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Tee valik Meeldib"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Tühista valik Ei meeldi"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Tee valik Ei meeldi"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Ära korda midagi"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Korda kõiki"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Korda ühte"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Luba juhuslikus järjekorras esitamine"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Keela juhuslikus järjekorras esitamine"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Luba kvaliteetne taasesitus"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Keela kvaliteetne taasesitus"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Luba subtiitrid"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Keela subtiitrid"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Sisene režiimi Pilt pildis"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Meedia juhtnupud on kuvatud"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Meedia juhtnupud on peidetud, kuvamiseks vajutage juhtimisklahvistikku"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Lõpeta"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Jätka"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"MediaPlayeri veakood %1$d, lisakood %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"ALUSTAGE"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Järgmine"</string>
+</resources>
diff --git a/leanback/src/main/res/values-eu/strings.xml b/leanback/src/main/res/values-eu/strings.xml
new file mode 100644
index 0000000..6b7226f
--- /dev/null
+++ b/leanback/src/main/res/values-eu/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="8126335323963415494">"Nabigazio-menua"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Bilaketa"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Bilatu"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Esan bilatu nahi duzuna"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Bilatu <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Hitz egin, bilaketa hemen egiteko: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Erreproduzitu"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Pausatu"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Aurreratu"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Aurreratu %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Atzeratu"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Atzeratu %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Saltatu hurrengora"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Saltatu aurrekora"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Ekintza gehiago"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Desautatu \"erpurua gora\""</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Hautatu \"erpurua gora\""</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Desautatu \"erpurua behera\""</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Hautatu \"erpurua behera\""</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Ez errepikatu"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Errepikatu guztiak"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Errepikatu bat"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Gaitu ausazko erreprodukzioa"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Desgaitu ausazko erreprodukzioa"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Gaitu kalitate handiko erreprodukzioa"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Desgaitu kalitate handiko erreprodukzioa"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Gaitu azpitituluak"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Desgaitu azpitituluak"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Aktibatu \"Pantaila txiki gainjarri\" modua"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Multimedia kontrolatzeko aukerak ikusgai"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Ezkutatuta daude multimedia-edukia kontrolatzeko aukerak. Erakusteko, sakatu nabigazio-gurutzea."</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Amaitu"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Egin aurrera"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"MediaPlayer errore-kodea: %1$d (%2$d gehigarria)"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"HASI ERABILTZEN"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Aurrera"</string>
+</resources>
diff --git a/leanback/src/main/res/values-fa/strings.xml b/leanback/src/main/res/values-fa/strings.xml
new file mode 100644
index 0000000..cadc59f
--- /dev/null
+++ b/leanback/src/main/res/values-fa/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="8126335323963415494">"منوی پیمایش"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"عملکرد جستجو"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"جستجو"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"برای جستجو صحبت کنید"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"جستجوی <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"جستجو با گفتن <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"پخش"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"مکث"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"جلو بردن سریع"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"‏جلو بردن سریع ‎%1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"عقب بردن"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"‏عقب بردن ‎%1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"رد شدن از بعدی"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"رد شدن از قبلی"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"اقدام‌های بیشتر"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"لغو انتخاب رأی موافق"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"انتخاب رأی موافق"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"لغو انتخاب رأی مخالف"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"انتخاب رأی مخالف"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"تکرار هیچ‌کدام"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"تکرار همه"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"یک‌بار تکرار"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"فعال کردن پخش تصادفی"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"غیرفعال کردن پخش تصادفی"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"فعال کردن کیفیت بالا"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"غیرفعال کردن کیفیت بالا"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"فعال کردن زیرنویس"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"غیرفعال کردن زیرنویس"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"وارد شدن به حالت تصویر در تصویر"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"کنترل‌های رسانه نشان داده می‌شود"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"کنترل‌های رسانه پنهان است، برای نمایش آن‌ها پد کنترل را فشار دهید"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"پایان"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"ادامه"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"‏کد خطای MediaPlayer‏ %1$d extra %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"شروع به کار"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"بعدی"</string>
+</resources>
diff --git a/leanback/src/main/res/values-fi/strings.xml b/leanback/src/main/res/values-fi/strings.xml
new file mode 100644
index 0000000..f3ee15e
--- /dev/null
+++ b/leanback/src/main/res/values-fi/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="8126335323963415494">"Navigointivalikko"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Hakutoiminto"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Haku"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Hae puhumalla"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Haku: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Puhehaku: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Toista"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Keskeytä"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Kelaa eteenpäin"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Kelaa eteenpäin %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Kelaa taaksepäin"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Kelaa taaksepäin %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Siirry seuraavaan"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Siirry edelliseen"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Lisää toimintoja"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Poista Tykkään-valinta"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Valitse Tykkään"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Poista En tykkää ‑valinta"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Valitse En tykkää"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Ei uudelleentoistoa"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Toista kaikki uudelleen"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Toista yksi uudelleen"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Ota satunnaistoisto käyttöön"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Poista satunnaistoisto käytöstä"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Ota korkea laatu käyttöön"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Poista korkea laatu käytöstä"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Ota tekstitys käyttöön"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Poista tekstitys käytöstä"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Vaihda kuva kuvassa ‑tilaan"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Mediasäätimet näkyvissä"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Mediasäätimet piilotettu, näytä painamalla suuntanäppäimiä."</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Valmis"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Jatka"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"MediaPlayerin virhekoodi %1$d ylimääräinen %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"ALOITA"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Seuraava"</string>
+</resources>
diff --git a/leanback/src/main/res/values-fr-rCA/strings.xml b/leanback/src/main/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..de3fde5
--- /dev/null
+++ b/leanback/src/main/res/values-fr-rCA/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="8126335323963415494">"Menu de navigation"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Action de recherche"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Rechercher"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Énoncez votre recherche"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Rechercher dans <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Énoncez votre recherche dans <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Lire"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Pause"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Avance rapide"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Avance rapide à %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Retour arrière"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Retour rapide à %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Passer à l\'élément suivant"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Passer à l\'élément précédent"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Autres actions"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Désélectionner la mention « J\'aime »"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Sélectionner la mention « J\'aime »"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Désélectionner la mention « Je n\'aime pas »"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Sélectionner la mention « Je n\'aime pas »"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Aucune répétition"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Tout lire en boucle"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Répéter un élément"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Activer la lecture aléatoire"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Désactiver la lecture aléatoire"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Activer la lecture haute qualité"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Désactiver la lecture haute qualité"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Activer le sous-titrage"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Désactiver le sous-titrage"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Activer le mode Incrustation d\'image"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Les commandes multimédias sont affichées"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Les commandes multimédias sont masquées, appuyez sur le pavé directionnel pour les afficher."</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Terminer"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Continuer"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"Code d\'erreur MediaPlayer %1$d extra %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"COMMENCER"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Suivant"</string>
+</resources>
diff --git a/leanback/src/main/res/values-fr/strings.xml b/leanback/src/main/res/values-fr/strings.xml
new file mode 100644
index 0000000..7436842
--- /dev/null
+++ b/leanback/src/main/res/values-fr/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="8126335323963415494">"Menu de navigation"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Commande de recherche"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Rechercher"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Énoncez votre recherche"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Rechercher dans <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Énoncez votre recherche dans <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Lecture"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Pause"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Avance rapide"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Avance rapide de %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Retour arrière"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Retour arrière de %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Ignorer l\'élément suivant"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Ignorer l\'élément précédent"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Autres actions"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Annuler J\'aime"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Sélectionner J\'aime"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Annuler Je n\'aime pas"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Sélectionner Je n\'aime pas"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Ne rien lire en boucle"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Tout lire en boucle"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Lire en boucle un élément"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Activer la lecture en mode aléatoire"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Désactiver la lecture en mode aléatoire"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Activer la haute qualité"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Désactiver la haute qualité"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Activer les sous-titres"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Désactiver les sous-titres"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Activer le mode Picture-in-picture"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Les commandes multimédias sont affichées"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Les commandes multimédias sont masquées. Appuyez sur le pavé directionnel pour les afficher"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Terminer"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Continuer"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"Code d\'erreur MediaPlayer %1$d extra %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"COMMENCER"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Suivante"</string>
+</resources>
diff --git a/leanback/src/main/res/values-gl/strings.xml b/leanback/src/main/res/values-gl/strings.xml
new file mode 100644
index 0000000..b256f20
--- /dev/null
+++ b/leanback/src/main/res/values-gl/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="8126335323963415494">"Menú de navegación"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Acción de busca"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Busca"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Fala para efectuar a busca"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Busca <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Fala para buscar <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Reproducir"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Pausar"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Avance rápido"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Avance rápido %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Rebobinar"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Rebobinado %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Saltar ao seguinte"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Saltar ao anterior"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Máis accións"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Anular Gústame"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Seleccionar Gústame"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Anular Non me gusta"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Seleccionar Non me gusta"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Non repetir"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Repetir todo"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Repetir unha pista"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Activar reprodución aleatoria"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Desactivar reprodución aleatoria"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Activar alta calidade"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Desactivar alta calidade"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Activar subtítulos"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Desactivar subtítulos"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Activar modo Pantalla superposta"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Móstranse os controis de recursos multimedia"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Os controis de recursos multimedia están ocultos. Preme o botón direccional para mostralos"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Finalizar"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Continuar"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"Código de erro de MediaPlayer %1$d %2$d de máis"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"COMEZAR"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Seguinte"</string>
+</resources>
diff --git a/leanback/src/main/res/values-gu/strings.xml b/leanback/src/main/res/values-gu/strings.xml
new file mode 100644
index 0000000..a6bdbb8
--- /dev/null
+++ b/leanback/src/main/res/values-gu/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="8126335323963415494">"નૅવિગેશન મેનૂ"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"શોધવાની ક્રિયા"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"શોધો"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"શોધવા માટે બોલો"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> શોધો"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>ને શોધવા માટે બોલો"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"ચલાવો"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"થોભાવો"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"ફાસ્ટ ફૉરવર્ડ કરો"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"%1$dX ને ફાસ્ટ ફૉરવર્ડ કરો"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"રિવાઇન્ડ કરો"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"%1$dX ને રિવાઇન્ડ કરો"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"આગળના પર જાઓ"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"પાછળના પર જાઓ"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"વધુ ક્રિયાઓ"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"થમ્બ્સ અપને નાપસંદ કરો"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"થમ્બ્સ અપને પસંદ કરો"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"થમ્બ્સ ડાઉનને નાપસંદ કરો"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"થમ્બ્સ ડાઉનને પસંદ કરો"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"કોઈ રિપીટ કરતા નહીં"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"બધાને રિપીટ કરો"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"એક મીડિયા રિપીટ કરો"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"શફલ કરવું ચાલુ કરો"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"શફલ કરવું બંધ કરો"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"ઉચ્ચ ક્વૉલિટી ચાલુ કરો"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"ઉચ્ચ ક્વૉલિટી બંધ કરો"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"ઉપશીર્ષક બતાવવાનું ચાલુ કરો"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"ઉપશીર્ષક બતાવવાનું બંધ કરો"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"ચિત્ર-માં-ચિત્ર મોડમાં દાખલ થાઓ"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"મીડિયા નિયંત્રણો બતાવેલા છે"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"મીડિયા નિયંત્રણો છુપાયેલા છે, તે બતાવવા માટે ડી-પૅડ દબાવો"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"સમાપ્ત કરો"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"આગળ વધો"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"MediaPlayer ભૂલનો કોડ %1$d અતિરિક્ત %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"પ્રારંભ કરો"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"આગળ"</string>
+</resources>
diff --git a/leanback/src/main/res/values-hi/strings.xml b/leanback/src/main/res/values-hi/strings.xml
new file mode 100644
index 0000000..eed7ee3
--- /dev/null
+++ b/leanback/src/main/res/values-hi/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="8126335323963415494">"नेविगेशन मेन्यू"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"ज़्यादा विकल्प खाेजें"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"खोजें"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"बोलकर खोजें"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> खाेजें"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> खोजने के लिए बोलें"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"चलाएं"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"रोकें"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"तेज़ी से आगे बढ़ाएं"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"%1$dX तेज़ी से आगे बढ़ाएं"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"पीछे ले जाएं"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"%1$dX तेज़ी से पीछे ले जाएं"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"अगले पर जाएं"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"पिछले पर जाएं"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"ज़्यादा विकल्प"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"पसंद करने के विकल्प से चुना हुआ हटाएं"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"पसंद करने का विकल्प चुनें"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"नापसंद करने के विकल्प से चुना हुआ हटाएं"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"नापसंद का विकल्प चुनें"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"कुछ न दोहराएं"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"सभी को दोहराएं"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"एक काे दोहराएं"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"शफ़ल करने की सुविधा चालू करें"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"शफ़ल करने की सुविधा बंद करें"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"अच्छी क्वालिटी में चलाने की सुविधा चालू करें"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"अच्छी क्वालिटी में चलाने की सुविधा बंद करें"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"सबटाइटल की सुविधा चालू करें"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"सबटाइटल की सुविधा बंद करें"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"पिक्चर में पिक्चर माेड चालू करें"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"माैजूदा मीडिया नियंत्रण"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"मीडिया नियंत्रण छिपे हुए हैं, स्क्रीन पर दिखाने के लिए डी-पैड दबाएं"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"खत्म करें"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"जारी रखें"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"मीडिया प्लेयर का गड़बड़ी कोड %1$d और %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"शुरू करें"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"आगे जाएं"</string>
+</resources>
diff --git a/leanback/src/main/res/values-hr/strings.xml b/leanback/src/main/res/values-hr/strings.xml
new file mode 100644
index 0000000..1d26d99
--- /dev/null
+++ b/leanback/src/main/res/values-hr/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="8126335323963415494">"Navigacijski izbornik"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Radnja pretraživanja"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Pretražite"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Izgovorite upit za pretraživanje"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Tražite <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Izgovorite upit za pretraživanje <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Pokreni"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Pauza"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Brzo unaprijed"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Brzo unaprijed %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Unatrag"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Unatrag %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Preskoči na sljedeće"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Preskoči na prethodno"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Više radnji"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Poništi odabir palca gore"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Odaberi palac gore"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Poništi odabir palca dolje"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Odaberi palac dolje"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Bez ponavljanja"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Ponovi sve"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Ponovi jedno"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Omogući nasumičnu reprodukciju"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Onemogući nasumičnu reprodukciju"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Omogući visoku kvalitetu"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Onemogući visoku kvalitetu"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Omogući titlove"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Onemogući titlove"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Pokretanje načina slike u slici"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Medijske kontrole prikazane"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Medijske kontrole skrivene su, pritisnite D-pad za prikaz"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Završi"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Nastavi"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"Kôd pogreške MediaPlayera: %1$d, dodatno %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"POČETAK"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Dalje"</string>
+</resources>
diff --git a/leanback/src/main/res/values-hu/strings.xml b/leanback/src/main/res/values-hu/strings.xml
new file mode 100644
index 0000000..a27d394
--- /dev/null
+++ b/leanback/src/main/res/values-hu/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="8126335323963415494">"Navigációs menü"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Keresési művelet"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Keresés"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Beszéljen a keresés indításához"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Keresés itt: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Mondjon valamit, hogy itt keressen: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Lejátszás"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Szünet"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Gyors előretekerés"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Előretekerés %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Visszatekerés"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Visszatekerés %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Ugrás a következőre"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Ugrás az előzőre"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"További műveletek"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"„Tetszik” értékelés visszavonása"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"„Tetszik” értékelés kiválasztása"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"„Nem tetszik” értékelés visszavonása"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"„Nem tetszik” értékelés kiválasztása"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Nincs ismétlés"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Összes ismétlése"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Egy ismétlése"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Véletlenszerű lejátszás engedélyezése"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Véletlenszerű lejátszás letiltása"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Jó minőségű lejátszás engedélyezése"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Jó minőségű lejátszás letiltása"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Feliratok engedélyezése"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Feliratok letiltása"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Kép a képben mód indítása"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Médiavezérlők megjelenítve"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"A médiavezérlők el vannak rejtve. Megjelenítésükhöz nyomja le a d-padet."</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Befejezés"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Tovább"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"MediaPlayer-hibakód: %1$d extra %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"KEZDŐ LÉPÉSEK"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Tovább"</string>
+</resources>
diff --git a/leanback/src/main/res/values-hy/strings.xml b/leanback/src/main/res/values-hy/strings.xml
new file mode 100644
index 0000000..8a4036b
--- /dev/null
+++ b/leanback/src/main/res/values-hy/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="8126335323963415494">"Նավարկման ընտրացանկ"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Որոնում"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Որոնում"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Խոսեք՝ որոնելու համար"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Որոնեք <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Խոսեք՝ <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> որոնելու համար"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Նվագարկել"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Ընդհատել"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Առաջ գնալ"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Առաջ գնալ՝ %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Հետ գնալ"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Հետ գնալ՝ %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Անցնել հաջորդին"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Անցնել նախորդին"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Այլ գործողություններ"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Չեղարկել «Հավանում եմ»-ը"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Սեղմել «Հավանում եմ»"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Չեղարկել «Չեմ հավանում»-ը"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Սեղմել «Չեմ հավանում»"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Չկրկնել"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Կրկնել բոլորը"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Կրկնել մեկը"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Միացնել խառը նվագարկումը"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Անջատել խառը նվագարկումը"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Միացնել բարձր որակը"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Անջատել բարձր որակը"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Միացնել ենթագրերը"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Անջատել ենթագրերը"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Միացնել «Նկար նկարի մեջ» ռեժիմը"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Մեդիայի կառավարման տարրերը ցուցադրված են"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Մեդիայի կառավարման տարրերը թաքցված են։ Ցուցադրելու համար սեղմեք D-pad-ը:"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Ավարտել"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Շարունակել"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"Մեդիա նվագարկիչի սխալի կոդ` %1$d (լրացուցիչ %2$d)"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"ՍԿՍԵL"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Հաջորդը"</string>
+</resources>
diff --git a/leanback/src/main/res/values-in/strings.xml b/leanback/src/main/res/values-in/strings.xml
new file mode 100644
index 0000000..85d92a8
--- /dev/null
+++ b/leanback/src/main/res/values-in/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="8126335323963415494">"Menu navigasi"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Tindakan Penelusuran"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Telusuri"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Ucapkan untuk menelusuri"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Telusuri <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Ucapkan untuk menelusuri <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Putar"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Jeda"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Maju"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Maju %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Mundur"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Mundur %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Lewati ke Berikutnya"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Lewati ke Sebelumnya"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Tindakan Lainnya"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Batal Pilih Yang Disukai"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Pilih Yang Disukai"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Batal Pilih Yang Tidak Disukai"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Pilih Yang Tidak Disukai"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Jangan Ulangi"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Ulangi Semua"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Ulangi 1"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Aktifkan Acak"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Nonaktifkan Acak"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Aktifkan Kualitas Tinggi"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Nonaktifkan Kualitas Tinggi"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Aktifkan Pemberian Subtitel"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Nonaktifkan Pemberian Subtitel"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Masuk Mode Picture In Picture"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Kontrol media ditampilkan"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Kontrol media disembunyikan, tekan d-pad untuk menampilkannya"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Selesai"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Lanjutkan"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"Kode error MediaPlayer %1$d ekstra %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"MULAI"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Berikutnya"</string>
+</resources>
diff --git a/leanback/src/main/res/values-is/strings.xml b/leanback/src/main/res/values-is/strings.xml
new file mode 100644
index 0000000..0c12c62
--- /dev/null
+++ b/leanback/src/main/res/values-is/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="8126335323963415494">"Yfirlitsvalmynd"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Leitaraðgerð"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Leita"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Talaðu til að leita"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Leita í <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Talaðu til að leita í <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Spila"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Hlé"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Spóla áfram"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Spóla áfram %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Spóla til baka"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Spóla til baka %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Fara í næsta"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Fara í fyrra"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Fleiri aðgerðir"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Hætta við þumal upp"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Gefa þumal upp"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Hætta við þumal niður"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Gefa þumal niður"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Endurtaka ekkert"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Endurtaka allt"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Endurtaka eitt"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Kveikja á stokkun"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Slökkva á stokkun"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Kveikja á miklum gæðum"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Slökkva á miklum gæðum"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Kveikja á skjátextum"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Slökkva á skjátextum"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Skoða mynd í myndsniði"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Spilunarstýringar sýndar"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Spilunarstýringar faldar, ýttu á stefnuhnappa til að sýna þær"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Ljúka"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Áfram"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"Villukóði MediaPlayer %1$d aukalegt %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"HEFJAST HANDA"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Áfram"</string>
+</resources>
diff --git a/leanback/src/main/res/values-it/strings.xml b/leanback/src/main/res/values-it/strings.xml
new file mode 100644
index 0000000..ead1577
--- /dev/null
+++ b/leanback/src/main/res/values-it/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="8126335323963415494">"Menu di navigazione"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Azione di ricerca"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Cerca"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Parla per cercare"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Cerca in <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Parla per cercare in <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Riproduci"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Metti in pausa"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Avanti veloce"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Avanti veloce: %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Riavvolgi"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Riavvolgi: %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Passa ai contenuti successivi"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Passa ai contenuti precedenti"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Altre azioni"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Deseleziona Mi piace"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Seleziona Mi piace"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Deseleziona Non mi piace"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Seleziona Non mi piace"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Non ripetere nulla"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Ripeti tutti"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Ripeti uno"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Attiva la riproduzione casuale"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Disattiva la riproduzione casuale"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Attiva alta qualità"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Disattiva alta qualità"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Attiva sottotitoli"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Disattiva sottotitoli"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Attiva la modalità Picture in picture"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Controlli multimediali visualizzati"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Controlli multimediali nascosti, premi il d-pad per visualizzarli"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Fine"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Continua"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"Codice di errore MediaPlayer %1$d extra %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"INIZIA"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Avanti"</string>
+</resources>
diff --git a/leanback/src/main/res/values-iw/strings.xml b/leanback/src/main/res/values-iw/strings.xml
new file mode 100644
index 0000000..7f02b2e
--- /dev/null
+++ b/leanback/src/main/res/values-iw/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="8126335323963415494">"תפריט ניווט"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"פעולת חיפוש"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"חיפוש"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"יש לדבר בקול כדי לחפש"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"חיפוש של <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"יש לדבר כדי לחפש את <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"‎%1$dX‎‎"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"‎%1$dX‎‎"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"הפעלה"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"השהיה"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"הרצה קדימה"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"‏הרצה קדימה של %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"הרצה אחורה"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"‏הרצה אחורה של %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"דילוג אל הפריט הבא"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"דילוג אל הפריט הקודם"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"פעולות נוספות"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"ביטול בחירה בסימון \'אהבתי\'"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"בחירה בסימון \'אהבתי\'"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"ביטול בחירה בסימון \'לא אהבתי\'"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"בחירה בסימון \'לא אהבתי\'"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"אל תחזור על כלום"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"חזור על הכול"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"חזור על פריט אחד"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"הפעלת ערבוב"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"השבתת ערבוב"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"הפעלת איכות גבוהה"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"השבתת איכות גבוהה"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"הפעלת כתוביות"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"השבתת כתוביות"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"מעבר למצב תמונה בתוך תמונה"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"פקדי המדיה מוצגים"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"‏פקדי המדיה מוסתרים. יש להקיש על ה-d-pad כדי להציג אותם"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"סיום"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"המשך"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"‏קוד שגיאה %1$d‏ של MediaPlayer ועוד %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"קדימה, לעבודה"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"הבא"</string>
+</resources>
diff --git a/leanback/src/main/res/values-ja/strings.xml b/leanback/src/main/res/values-ja/strings.xml
new file mode 100644
index 0000000..22980f1
--- /dev/null
+++ b/leanback/src/main/res/values-ja/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="8126335323963415494">"ナビゲーション メニュー"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"検索操作"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"検索"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"音声検索"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> を検索"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> を音声検索"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"再生"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"一時停止"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"早送り"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"早送り %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"巻き戻し"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"巻き戻し %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"次の曲にスキップ"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"前の曲にスキップ"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"その他の操作"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"高評価の選択を解除"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"高評価を選択"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"低評価の選択を解除"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"低評価を選択"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"リピートなし"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"全曲をリピート"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"1 曲をリピート"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"シャッフルを有効にする"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"シャッフルを無効にする"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"高品質を有効にする"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"高品質を無効にする"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"クローズド キャプションを有効にする"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"クローズド キャプションを無効にする"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"ピクチャー イン ピクチャー モードに移動"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"メディア コントロールは表示されています"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"メディア コントロールは非表示になっています。表示するには D-pad を押してください"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"終了"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"続行"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"MediaPlayer エラーコード: %1$d、追加: %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"使ってみる"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"次へ"</string>
+</resources>
diff --git a/leanback/src/main/res/values-ka/strings.xml b/leanback/src/main/res/values-ka/strings.xml
new file mode 100644
index 0000000..2f61e14
--- /dev/null
+++ b/leanback/src/main/res/values-ka/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="8126335323963415494">"ნავიგაციის მენიუ"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"ძიების მოქმედება"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"ძიება"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"თქვით საძიებო ფრაზა"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>-ის ძიება"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"თქვით <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>-ის საძიებლად"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"დაკვრა"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"პაუზა"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"წინ გადახვევა"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"სწრაფი გადამისამართება %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"უკან გადახვევა"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"გადახვევა %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"შემდეგის გამოტოვება"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"წინას გამოტოვება"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"დამატებითი ქმედებები"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"მაღალი შეფასების არჩევის გაუქმება"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"მაღალი შეფასების არჩევა"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"დაბალი შეფასების არჩევის გაუქმება"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"დაბალი შეფასების არჩევა"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"არცერთის გამეორება"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"ყველას გამეორება"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"ერთის გამეორება"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"არეულად დაკვრის ჩართვა"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"არეულად დაკვრის გამორთვა"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"მაღალი ხარისხის ჩართვა"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"მაღალი ხარისხის გამორთვა"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"დახურული წარწერების ჩართვა"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"დახურული წარწერების გაუქმება"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"რეჟიმზე „ეკრანი ეკრანში“ გადასვლა"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"ნაჩვენებია მედიის მართვის საშუალებები"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"მედიის მართვის საშუალებები დამალულია, გამოსაჩენად დააჭირეთ D-pad-ს"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"დასრულება"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"გაგრძელება"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"MediaPlayer-ის შეცდომის კოდი: %1$d extra %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"დაწყება"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"შემდეგი"</string>
+</resources>
diff --git a/leanback/src/main/res/values-kk/strings.xml b/leanback/src/main/res/values-kk/strings.xml
new file mode 100644
index 0000000..742aeaa
--- /dev/null
+++ b/leanback/src/main/res/values-kk/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="8126335323963415494">"Навигация мәзірі"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Іздеу әрекеті"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Іздеу"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Іздеу үшін сөйлеңіз"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> іздеу"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> іздеу үшін сөйлеңіз"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Ойнату"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Кідірту"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Алға айналдыру"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"%1$dX алға айналдыру"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Артқа айналдыру"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"%1$dX артқа айналдыру"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Келесіге өту"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Алдыңғыға өту"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Қосымша әрекеттер"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"\"Ұнайды\" белгісін алу"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"\"Ұнайды\" белгісін қою"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"\"Ұнамайды\" белгісін алу"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"\"Ұнамайды\" белгісін қою"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Ешқайсысын қайталамау"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Барлығын қайталау"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Біреуін қайталау"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Еркін ойнатуды қосу"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Еркін ойнатуды өшіру"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Жоғары сапаны қосу"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Жоғары сапаны өшіру"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Субтитрлерді қосу"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Cубтитрлерді өшіру"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"\"Сурет ішіндегі сурет\" режиміне кіру"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Мультимедианы басқару элементтері көрсетілген"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Мультимедианы басқару элементтері жасырылған, оларды көрсету үшін бағыт пернесін басыңыз"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Аяқтау"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Жалғастыру"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"MediaPlayer қате коды: %1$d, қосымша: %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"БАСТАУ"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Келесі"</string>
+</resources>
diff --git a/leanback/src/main/res/values-km/strings.xml b/leanback/src/main/res/values-km/strings.xml
new file mode 100644
index 0000000..c6946d7
--- /dev/null
+++ b/leanback/src/main/res/values-km/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="8126335323963415494">"ម៉ឺនុយរុករក"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"​ស្វែងរក​សកម្មភាព"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"ស្វែងរក"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"និយាយ​​ដើម្បី​ស្វែងរក"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"ស្វែងរក <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"និយាយ​ដើម្បី​ស្វែងរក <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"ចាក់"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"ផ្អាក"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"ទៅមុខ​រហ័ស"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"ទៅមុខ​រហ័ស %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"ខា​ថយ​ក្រោយ"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"ខា​ថយ​ក្រោយ %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"រំលងទៅ​បន្ទាប់"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"រំលង​ទៅពី​មុន"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"សកម្មភាព​ច្រើន​ទៀត"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"ឈប់​ជ្រើស​រើស​ការ​លើក​មេដៃ"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"ជ្រើសរើស​ការ​លើកមេ​ដៃ"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"ឈប់​ជ្រើស​រើស​ការឲ្យ​មេដៃ​ចុះ"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"ជ្រើស​រើស​ការឲ្យ​មេ​ដៃ​ចុះ"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"មិន​ចាក់​ឡើង​វិញ​"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"ចាក់​ឡើងវិញ​ទាំងអស់"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"ចាក់​ឡើងវិញ​មួយ"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"បើក​ការ​​ច្របល់"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"បិទ​ការ​ច្របល់"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"បើក​គុណភាព​ខ្ពស់"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"បិទ​គុណភាព​ខ្ពស់"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"បើក​អក្សរ​រត់"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"បិទ​អក្សរ​រត់"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"បញ្ចូល​មុខងារ​រូបក្នុងរូប"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"ការ​គ្រប់គ្រង​មេឌៀ​ត្រូវ​បាន​បង្ហាញ"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"ការ​គ្រប់គ្រង​មេឌៀ​ត្រូវ​បាន​លាក់ សូមចុច d-pad ដើម្បី​បង្ហាញ"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"បញ្ចប់"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"បន្ត"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"លេខកូដ​បញ្ហា​ MediaPlayer %1$d extra %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"ចាប់ផ្ដើម"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"បន្ទាប់"</string>
+</resources>
diff --git a/leanback/src/main/res/values-kn/strings.xml b/leanback/src/main/res/values-kn/strings.xml
new file mode 100644
index 0000000..509ffa9
--- /dev/null
+++ b/leanback/src/main/res/values-kn/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="8126335323963415494">"ನ್ಯಾವಿಗೇಶನ್‌ ಮೆನು"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"ಹುಡುಕಾಟ ಕ್ರಿಯೆ"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"ಹುಡುಕಿ"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"ಹುಡುಕಲು ಮಾತನಾಡಿ"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> ಹುಡುಕಿ"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> ಮಾತನಾಡಿ ಹುಡುಕಾಟ ನಡೆಸಿ"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"ಪ್ಲೇ"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"ವಿರಾಮ"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"ಫಾಸ್ಟ್ ಫಾರ್ವರ್ಡ್"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"ಫಾಸ್ಟ್ ಫಾರ್ವರ್ಡ್ %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"ರಿವೈಂಡ್"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"ರಿವೈಂಡ್ %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"ಮುಂದೆ ಸ್ಕಿಪ್ ಮಾಡಿ"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"ಹಿಂದೆ ಸ್ಕಿಪ್ ಮಾಡಿ"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"ಇನ್ನಷ್ಟು ಕ್ರಿಯೆಗಳು"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"ಥಂಬ್ ಅಪ್ ಆಯ್ಕೆರದ್ದುಮಾಡಿ"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"ಥಂಬ್ ಅಪ್ ಆಯ್ಕೆಮಾಡಿ"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"ಥಂಬ್ ಡೌನ್ ಆಯ್ಕೆರದ್ದುಮಾಡಿ"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"ಥಂಬ್ ಡೌನ್ ಆಯ್ಕೆಮಾಡಿ"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"ಯಾವುದನ್ನೂ ಪುನರಾವರ್ತಿಸಬೇಡಿ"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"ಎಲ್ಲವನ್ನು ಪುನರಾವರ್ತಿಸಿ"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"ಒಂದನ್ನು ಪುನರಾವರ್ತಿಸಿ"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"ಶಫಲ್ ಮಾಡುವುದನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"ಶಫಲ್ ಮಾಡುವುದನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"ಹೆಚ್ಚು ಗುಣಮಟ್ಟವನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"ಹೆಚ್ಚು ಗುಣಮಟ್ಟವನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"ಮುಚ್ಚಿದ ಶೀರ್ಷಿಕೆಯನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"ಮುಚ್ಚಿದ ಶೀರ್ಷಿಕೆಯನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"ಚಿತ್ರವನ್ನು ಚಿತ್ರ ಮೋಡ್‌ನಲ್ಲಿ ಪ್ರವೇಶಿಸಿ"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"ಮಾಧ್ಯಮ ನಿಯಂತ್ರಣಗಳನ್ನು ತೋರಿಸಲಾಗಿದೆ"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"ಮಾಧ್ಯಮ ನಿಯಂತ್ರಣಗಳನ್ನು ಮರೆಮಾಡಲಾಗಿದೆ, ತೋರಿಸಲು d-pad ಒತ್ತಿರಿ"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"ಪೂರ್ಣಗೊಳಿಸಿ"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"ಮುಂದುವರಿಸಿ"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"ಮೀಡಿಯಾ ಪ್ಲೇಯರ್ ದೋಷ ಕೋಡ್ %1$d ಹೆಚ್ಚುವರಿ %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"ಪ್ರಾರಂಭಿಸಿ"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"ಮುಂದೆ"</string>
+</resources>
diff --git a/leanback/src/main/res/values-ko/strings.xml b/leanback/src/main/res/values-ko/strings.xml
new file mode 100644
index 0000000..9eacb53
--- /dev/null
+++ b/leanback/src/main/res/values-ko/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="8126335323963415494">"탐색 메뉴"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"검색 작업"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"검색"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"음성 검색"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> 검색"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> 음성 검색"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$d배속"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$d배속"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"재생"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"일시중지"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"빨리 감기"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"%1$d배속 빨리 감기"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"되감기"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"%1$d배속 되감기"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"다음으로 건너뛰기"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"이전으로 건너뛰기"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"추가 작업"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"좋아요 선택 해제"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"좋아요 선택"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"싫어요 선택 해제"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"싫어요 선택"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"반복 안함"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"전체 반복"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"한 항목 반복"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"셔플 사용 설정"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"셔플 사용 중지"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"고품질 사용 설정"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"고품질 사용 중지"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"자막 사용 설정"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"자막 사용 중지"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"PIP 모드 시작"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"미디어 컨트롤이 표시되었습니다."</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"미디어 컨트롤이 숨겨져 있습니다. 표시하려면 D패드를 누르세요."</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"완료"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"계속"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"MediaPlayer 오류 코드 %1$d extra %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"시작하기"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"다음"</string>
+</resources>
diff --git a/leanback/src/main/res/values-ky/strings.xml b/leanback/src/main/res/values-ky/strings.xml
new file mode 100644
index 0000000..12f3255
--- /dev/null
+++ b/leanback/src/main/res/values-ky/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="8126335323963415494">"Чабыттоо менюсу"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Издөө аракети"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Издөө"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Издөө үчүн сүйлөңүз"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> издөө"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> издөө үчүн сүйлөңүз"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Угуу"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Тыным"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Алдыга түрүү"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Алдыга түрүү %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Артка түрүү"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Артка түрүү %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Кийинкини өткөрүп жиберүү"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Мурункуну өткөрүп жиберүү"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Дагы көнүгүүлөр"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"\"Жакты\" белгисин өчүрүү"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Жакты деп белгилөө"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Жактырбоону тандоодон чыгаруу"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Жактырбоону тандоо"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Эч бирин кайталабоо"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Баарын кайталоо"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Бирөөнү кайталоо"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Аралаштырууну иштетүү"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Аралаштырууну өчүрүү"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Жогорку сапатты иштетүү"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Жогорку сапатты өчүрүү"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Жабык субтитрлерди иштетүү"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Жабык субтитрлерди өчүрүү"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Сүрөт режиминде сүрөт киргизүү"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Медиа файлды башкаруу көрсөтүлдү"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Медиа файлды башкаруу жашырылган, көрүү үчүн d-pad көзөмөлдөө каражатын басыңыз"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Бүттү"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Улантуу"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"MediaPlayer\'деги катанын коду: %1$d, кошумча: %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"БАШТОО"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Кийинки"</string>
+</resources>
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/src/main/res/values-lo/strings.xml b/leanback/src/main/res/values-lo/strings.xml
new file mode 100644
index 0000000..a188b25
--- /dev/null
+++ b/leanback/src/main/res/values-lo/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="8126335323963415494">"ເມນູນຳທາງ"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"ຊອກຫາຄຳສັ່ງ"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"ຊອກຫາ"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"ເວົ້າເພື່ອຊອກຫາ"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"ຊອກຫາ <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"ເວົ້າເພື່ອຊອກຫາ <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"ຫຼິ້ນ"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"ຢຸດຊົ່ວຄາວ"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"ເລື່ອນໄປໜ້າ"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"ເລື່ອນໄປໜ້າ %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"ເລື່ອນກັບຫຼັງ"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"ເລື່ອນກັບຫຼັງ %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"ຂ້າມໄປອັນໜ້າ"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"ຂ້າມໄປອັນກ່ອນ"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"ຄຳສັ່ງເພີ່ມເຕີມ"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"ຢຸດເລືອກຍົກໂປ້ແລ້ວ"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"ເລືອກຍົກໂປ້ແລ້ວ"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"ຢຸດຊີ້ໂປ້ລົງແລ້ວ"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"ເລືອກຊີ້ໂປ້ລົງແລ້ວ"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"ບໍ່ຫຼິ້ນຊ້ຳ"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"ຫຼິ້ນຊ້ຳທັງໝົດ"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"ຫຼິ້ນຊ້ຳເທື່ອດຽວ"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"ເປີດນຳໃຊ້ການສະຫຼັບ"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"ປິດນຳໃຊ້ການສະຫຼັບ"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"ເປີດຄຸນນະພາບສູງ"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"ປິດຄຸນນະພາບສູງ"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"ເປີດນຳໃຊ້ຄຳບັນຍາຍແບບປິດ"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"ປິດນຳໃຊ້ຄຳບັນຍາຍແບບປິດ"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"ປ້ອນຮູບພາບໃນໂໝດຮູບພາບ"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"ສະແດງຕົວຄວບຄຸມມີເດຍແລ້ວ"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"ເຊື່ອງຕົວຄວບຄຸມມີເດຍແລ້ວ, ກົດປຸ່ມທິດທາງເພື່ອສະແດງ"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"ແລ້ວໆ"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"ສືບຕໍ່"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"ລະຫັດ MediaPlayer ຜິດພາດ %1$d ເພີ່ມເຕີມ %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"ເລີ່ມເລີຍ"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"ຕໍ່ໄປ"</string>
+</resources>
diff --git a/leanback/src/main/res/values-lt/strings.xml b/leanback/src/main/res/values-lt/strings.xml
new file mode 100644
index 0000000..e4e6741
--- /dev/null
+++ b/leanback/src/main/res/values-lt/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="8126335323963415494">"Naršymo meniu"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Paieškos veiksmas"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Ieškoti"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Pasakykite, kad ieškotumėte"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Ieškoti „<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>“"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Kalbėkite, kad ieškotumėte „<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>“"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$d k."</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$d k."</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Leisti"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Pristabdyti"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Sukti pirmyn"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Sukti pirmyn %1$d k. greičiau"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Sukti atgal"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Sukti atgal %1$d k. greičiau"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Praleisti kitą"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Praleisti ankstesnį"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Daugiau veiksmų"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Panaikinti parinkties „Patinka“ pasirinkimą"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Pasirinkti parinktį „Patinka“"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Panaikinti parinkties „Nepatinka“ pasirinkimą"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Pasirinkti parinktį „Nepatinka“"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Nekartoti nieko"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Kartoti viską"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Kartoti vieną"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Įgalinti maišymą"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Išjungti maišymą"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Įgalinti aukštą kokybę"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Išjungti aukštą kokybę"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Įgalinti subtitrus"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Išjungti subtitrus"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Įjungti vaizdo vaizde režimą"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Medijos valdikliai rodomi"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Medijos valdikliai paslėpti. Paspauskite valdymo pultą, kad būtų rodomi"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Užbaigti"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Tęsti"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"%1$d ir %2$d „MediaPlayer“ klaidos kodas"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"PRADĖTI"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Kitas"</string>
+</resources>
diff --git a/leanback/src/main/res/values-lv/strings.xml b/leanback/src/main/res/values-lv/strings.xml
new file mode 100644
index 0000000..db07d64
--- /dev/null
+++ b/leanback/src/main/res/values-lv/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="8126335323963415494">"Navigācijas izvēlne"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Meklēšanas darbība"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Meklēt"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Runāt, lai meklētu"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Meklējiet: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Runājiet, lai meklētu <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Atskaņot"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Pauzēt"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Pārtīt uz priekšu"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Pārtīt uz priekšu %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Attīt"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Attīt atpakaļ %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Izlaist nākamo"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Izlaist iepriekšējo"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Citas darbības"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Atcelt “Patīk” atlasi"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Atlasīt “Patīk”"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Atcelt “Nepatīk” atlasi"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Atlasīt “Nepatīk”"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Neatkārtot nevienu"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Atkārtot visu"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Atkārtot vienu"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Iespējot atskaņošanu jauktā secībā"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Atspējot atskaņošanu jauktā secībā"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Iespējot augstas kvalitātes vienumu atskaņošanu"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Atspējot augstas kvalitātes vienumu atskaņošanu"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Iespējot slēgtos parakstus"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Atspējot slēgtos parakstus"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Aktivizēt funkciju Attēls attēlā"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Multivides vadīklas ir redzamas."</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Multivides vadīklas ir paslēptas. Nospiediet virzienu tastatūru, lai tās tiktu parādītas."</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Pabeigt"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Turpināt"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"MediaPlayer kļūdas kods: %1$d extra %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"SĀKT DARBU"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Nākamā"</string>
+</resources>
diff --git a/leanback/src/main/res/values-mk/strings.xml b/leanback/src/main/res/values-mk/strings.xml
new file mode 100644
index 0000000..87df75b
--- /dev/null
+++ b/leanback/src/main/res/values-mk/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="8126335323963415494">"Мени за навигација"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Дејство на пребарување"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Пребарајте"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Зборувајте за да пребарувате"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Пребарувајте <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Кажете за да се пребарува <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Пушти"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Паузирај"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Премотај напред"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Премотај напред %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Премотај наназад"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Премотај наназад %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Прескокни на следна"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Прескокни на претходна"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Повеќе дејства"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Отштиклирај палец нагоре"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Штиклирај палец нагоре"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Отштиклирај палец надолу"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Штиклирај палец надолу"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Не повторувај ниедна"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Повтори ги сите"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Повтори една"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Овозможи мешање"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Оневозможи мешање"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Овозможи висок квалитет"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Оневозможи висок квалитет"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Овозможи затворени титлови"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Оневозможи затворени титлови"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Влези во режимот „Слика во слика“"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Контролите на аудиовизуелните датотеки се прикажани"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Контролите на аудиовизуелните датотеки се сокриени. Притиснете на навигациските копчиња за да се прикажат"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Готово"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Продолжи"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"Код за грешка на MediaPlayer %1$d дополнително %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"ЗАПОЧНЕТЕ"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Следно"</string>
+</resources>
diff --git a/leanback/src/main/res/values-ml/strings.xml b/leanback/src/main/res/values-ml/strings.xml
new file mode 100644
index 0000000..fab25dd
--- /dev/null
+++ b/leanback/src/main/res/values-ml/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="8126335323963415494">"നാവിഗേഷൻ മെനു"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"തിരയൽ പ്രവർത്തനം"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"തിരയുക"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"ശബ്‌ദം ഉപയോഗിച്ച് തിരയുക"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> തിരയുക"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> തിരയുന്നതിന് സംസാരിക്കുക"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"പ്ലേ ചെയ്യുക"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"താൽക്കാലികമായി നിർത്തുക"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"വേഗത്തിൽ മുന്നോട്ട് നീക്കുക"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"%1$dX വേഗത്തിൽ മുന്നോട്ട് നീക്കുക"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"പിന്നിലേക്ക് പോവുക"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"%1$dX റിവൈൻഡ് ചെയ്യുക"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"അടുത്തതിലേക്ക് പോകുക"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"മുമ്പത്തേതിലേക്ക് പോകുക"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"കൂടുതൽ പ്രവർത്തനങ്ങൾ"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"തമ്പ് അപ്പ് തിരഞ്ഞെടുത്തത് മാറ്റുക"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"തമ്പ് അപ്പ് തിരഞ്ഞെടുക്കുക"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"തമ്പ് ഡൗൺ തിരഞ്ഞെടുത്തത് മാറ്റുക"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"തമ്പ് ഡൗൺ തിരഞ്ഞെടുക്കുക"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"ഒന്നും ആവർത്തിക്കരുത്"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"എല്ലാം ആവർത്തിക്കുക"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"ഒന്ന് ആവർത്തിക്കുക"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"ഷഫിൾ ചെയ്യുന്നത് പ്രവർത്തനക്ഷമമാക്കുക"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"ഷഫിൾ ചെയ്യുന്നത് പ്രവർത്തനരഹിതമാക്കുക"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"ഉയർന്ന നിലവാരം പ്രവർത്തനക്ഷമമാക്കുക"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"ഉയർന്ന നിലവാരം പ്രവർത്തനരഹിതമാക്കുക"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"അടിക്കുറിപ്പ് നൽകൽ പ്രവർത്തനക്ഷമമാക്കുക"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"അടിക്കുറിപ്പ് നൽകൽ പ്രവർത്തനരഹിതമാക്കുക"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"\'ചിത്രത്തിനുള്ളിൽ ചിത്രം\' മോഡിലേക്ക് പ്രവേശിക്കുക"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"മീഡിയ നിയന്ത്രണങ്ങൾ ‌കാണിച്ചിരിക്കുന്നു"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"മീഡിയ നിയന്ത്രണങ്ങൾ ‌അദൃശ്യമാക്കിയിരിക്കുന്നു, കാണിക്കുന്നതിന് ഡി-‌പാഡ് അമർത്തുക"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"പൂർത്തിയാക്കുക"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"തുടരുക"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"മീഡിയ പ്ലേയർ പിശക് കോഡ് %1$d, കൂടെ %2$d എന്നതും"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"ആരംഭിക്കുക"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"അടുത്തത്"</string>
+</resources>
diff --git a/leanback/src/main/res/values-mn/strings.xml b/leanback/src/main/res/values-mn/strings.xml
new file mode 100644
index 0000000..8677caf
--- /dev/null
+++ b/leanback/src/main/res/values-mn/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="8126335323963415494">"Навигацийн цэс"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Хайлтын үйлдэл"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Хайх"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Хайхын тулд ярина уу"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> хайх"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> хайхын тулд ярина уу"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Тоглуулах"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Түр зогсоох"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Хурдан урагшлуулах"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Хурдан урагшлуулах %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Ухраах"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Ухраах %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Дараахийг алгасах"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Өмнөхийг алгасах"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Өөр үйлдлүүд"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Дээш  эрхий хурууны сонголтыг цуцлах"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Дээш эрхий хурууг сонгох"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Доош эрхий хурууны сонголтыг цуцлах"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Доош эрхий хурууг сонгох"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Алийг нь ч давтахгүй"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Бүгдийг давтах"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Нэгийг давтах"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Холихыг идэвхжүүлэх"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Холихыг идэвхгүй болгох"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Өндөр чанарыг идэвхжүүлэх"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Өндөр чанарыг идэвхгүй болгох"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Текст тайлбарыг идэвхжүүлэх"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Текст тайлбарыг идэвхгүй болгох"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Зурган доторх зураг горимд оруулна уу"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Медиа удирдлагыг харуулж байна"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Медиа удирдлага нуугдсан байна, харуулахын тулд d-pad-г дарна уу"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Дуусгах"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Үргэлжлүүлэх"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"MediaPlayer-н алдааны код %1$d нэмэлт %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"ЭХЛҮҮЛЭХ"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Дараах"</string>
+</resources>
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..b01e273
--- /dev/null
+++ b/leanback/src/main/res/values-mr/strings.xml
@@ -0,0 +1,65 @@
+<?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="8126335323963415494">"नेव्हिगेशन मेनू"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"शोध क्रिया"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"शोधा"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"शोधण्यासाठी बोला"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> शोधा"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> शोधण्यासाठी बोला"</string>
+    <!-- String.format failed for translation -->
+    <!-- no translation found for lb_control_display_fast_forward_multiplier (2721825378927619928) -->
+    <skip />
+    <!-- String.format failed for translation -->
+    <!-- no translation found for lb_control_display_rewind_multiplier (6173753802428649303) -->
+    <skip />
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"खेळा"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"विराम द्या"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"पुढे ढकला"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"फास्ट फॉरवर्ड %1$d"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"रीवाइंड करा"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"रीवाइंड %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"पुढील वगळा"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"मागील वगळा"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"आणखी क्रिया"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"वर अंगठा निवड रद्द करा"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"वर अंगठा निवडा"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"खाली अंगठा निवड रद्द करा"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"खाली अंगठा निवडा"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"काहीही रिपीट करू नका"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"सर्व रिपीट करा"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"एक रिपीट करा"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"शफल करा सुरू करा"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"शफल करा बंद करा"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"उच्च गुणवत्ता सुरू करा"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"उच्च गुणवत्ता बंद करा"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"सबटायटल बंद करा"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"सबटायटल बंद करा"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"चित्रात-चित्र मोडमध्ये एंटर करा"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"मीडिया नियंत्रणे दर्शवली आहेत"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"मीडिया नियंत्रणे लपलेली आहेत, दर्शवण्‍यासाठी d-pad दाबा"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"समाप्त"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"सुरू ठेवा"</string>
+    <!-- String.format failed for translation -->
+    <!-- no translation found for lb_media_player_error (8748646000835486516) -->
+    <skip />
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"सुरू करा"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"पुढील"</string>
+</resources>
diff --git a/leanback/src/main/res/values-ms/strings.xml b/leanback/src/main/res/values-ms/strings.xml
new file mode 100644
index 0000000..3af74cb
--- /dev/null
+++ b/leanback/src/main/res/values-ms/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="8126335323963415494">"Menu navigasi"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Tindakan Carian"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Cari"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Tutur untuk membuat carian"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Cari <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Tutur untuk mencari <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Main"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Jeda"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Mundar Laju"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Mundar Laju %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Mandir"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Mandir %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Langkau Seterusnya"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Langkau Sebelumnya"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Lagi Tindakan"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Nyahpilih Menyukai"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Pilih Menyukai"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Nyahpilih Tidak Menyukai"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Pilih Tidak Menyukai"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Jangan Ulang"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Ulang Semua"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Ulang Satu"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Dayakan Rombak"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Lumpuhkan Rombak"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Dayakan Kualiti Tinggi"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Lumpuhkan Kualiti Tinggi"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Dayakan Kapsyen Tertutup"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Lumpuhkan Kapsyen Tertutup"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Masuki Mod Gambar Dalam Gambar"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Kawalan media ditunjukkan"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Kawalan media disembunyikan, tekan d-pad untuk menunjukkan kawalan"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Selesai"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Teruskan"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"Kod ralat MediaPlayer %1$d tambahan %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"BERMULA"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Seterusnya"</string>
+</resources>
diff --git a/leanback/src/main/res/values-my/strings.xml b/leanback/src/main/res/values-my/strings.xml
new file mode 100644
index 0000000..1ded010
--- /dev/null
+++ b/leanback/src/main/res/values-my/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="8126335323963415494">"လမ်းညွှန် မီနူး"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"ရှာဖွေရန် လုပ်ဆောင်ချက်"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"ရှာဖွေရန်"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"ရှာဖွေရန် ပြောပါ"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> ကို ရှာဖွေရန်"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> ကို ရှာဖွေရန် ပြောပါ"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"ဖွင့်ရန်"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"ခဏရပ်ရန်"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"ရှေ့သို့ အမြန်သွားရန်"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"ရှေ့သို့ အမြန်သွားရန် %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"နောက်သို့ ရစ်ရန်"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"နောက်သို့ ရစ်ရန် %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"နောက်တစ်ပုဒ်သို့ ကျော်ရန်"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"ယခင်တစ်ပုဒ်သို့ သွားရန်"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"နောက်ထပ် လုပ်ဆောင်ချက်များ"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"လက်မထောင် သင်္ကေတအား မရွေးရန်"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"လက်မထောင် သင်္ကေတအား ရွေးရန်"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"လက်မအောက်စိုက် သင်္ကေတအား မရွေးရန်"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"လက်မအောက်စိုက် သင်္ကေတအား ရွေးရန်"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"မည်သည်ကိုမျှ ပြန်မကျော့ရန်"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"အားလုံး ပြန်ကျော့ရန်"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"တစ်ခုကို ပြန်ကျော့ရန်"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"ရောသမမွှေခြင်း ပြုရန်"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"ရောသမမွှေခြင်း မပြုရန်"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"\'အရည်အသွေးမြင့်\' ဖွင့်ရန်"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"\'အရည်အသွေးမြင့်\' ပိတ်ထားရန်"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"စာတမ်းများ ဖွင့်ရန်"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"စာတမ်းများ ပိတ်ရန်"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"\'တစ်ခုပေါ်တစ်ခုထပ်၍ ဖွင့်ခြင်းမုဒ်\' ကို ထည့်ရန်"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"မီဒီယာ ခလုတ်များကို ပြထားပါသည်"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"မီဒီယာခလုတ်များကို ဖျောက်ထားပါသည်။ ပြရန် d ခလုတ်ခုံကို နှိပ်ပါ"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"အပြီးသတ်ရန်"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"ရှေ့ဆက်ရန်"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"မီဒီယာပလေယာ မှားယွင်းမှုကုဒ် %1$d နှင့် အပို %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"စတင်ရန်"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"ရှေ့သို့"</string>
+</resources>
diff --git a/leanback/src/main/res/values-nb/strings.xml b/leanback/src/main/res/values-nb/strings.xml
new file mode 100644
index 0000000..99de7f6
--- /dev/null
+++ b/leanback/src/main/res/values-nb/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="8126335323963415494">"Navigasjonsmeny"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Søkehandling"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Søk"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Snakk for å søke"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Søk i <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Snakk for å søke i <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Spill av"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Sett på pause"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Spol fremover"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Spol fremover %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Spol tilbake"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Spol tilbake %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Hopp til neste"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Hopp til forrige"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Flere handlinger"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Fjern valg av «liker»"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Velg «liker»"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Fjern valg av «liker ikke»"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Velg «liker ikke»"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Ikke gjenta noen"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Gjenta alle"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Gjenta én"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Slå på avspilling i tilfeldig rekkefølge"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Slå av avspilling i tilfeldig rekkefølge"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Slå på høy kvalitet"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Slå av høy kvalitet"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Slå på teksting for hørselshemmede"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Slå av teksting for hørselshemmede"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Slå på bilde-i-bilde-modus"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Mediekontrollene vises"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Mediekontrollene er skjult – trykk på styrepilene for å vise dem"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Fullfør"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Fortsett"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"MediaPlayer-feilkode %1$d ekstra %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"KOM I GANG"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Neste"</string>
+</resources>
diff --git a/leanback/src/main/res/values-ne/strings.xml b/leanback/src/main/res/values-ne/strings.xml
new file mode 100644
index 0000000..416fc65
--- /dev/null
+++ b/leanback/src/main/res/values-ne/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="8126335323963415494">"नेभिगेसन मेनु"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"कारबाही खोज्नुहोस्"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"खोज्नुहोस्"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"खोज्नका लागि बोल्नुहोस्"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> खोज्नुहोस्"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> खोज्नका लागि बोल्नुहोस्"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"प्ले गर्नुहोस्"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"पज गर्नुहोस्"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"फास्ट फर्वार्ड गर्नुहोस्"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"फास्ट फर्वार्ड %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"रिवाइन्ड गर्नुहोस्"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"रिवाइन्ड गर्नुहोस् %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"अर्कोमा जानुहोस्"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"अघिल्लोमा जानुहोस्"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"थप कारबाहीहरू"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"मन परेको जनाउने बटनलाई चयनबाट हटाउनुहोस्"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"मन परेको जनाउने बटन चयन गर्नुहोस्"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"मन नपरेको जनाउने बटनलाई चयनबाट हटाउनुहोस्"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"मन नपरेको जनाउने बटन चयन गर्नुहोस्"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"कुनै पनि नदोहोर्‍याउनुहोला"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"सबै दोहोर्‍याउनुहोस्"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"एउटा दोहोर्‍याउनुहोस्"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"मिसाएर प्ले गर्ने सुविधा सक्षम पार्नुहोस्"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"मिसाएर प्ले गर्ने सुविधा असक्षम पार्नुहोस्"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"उच्च गुणस्तरलाई सक्षम पार्नुहोस्"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"उच्च गुणस्तरलाई असक्षम पार्नुहोस्"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"उप शीर्षकहरू देखाउने सुविधालाई सक्षम पार्नुहोस्"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"उप शीर्षकहरू देखाउने सुविधालाई असक्षम पार्नुहोस्"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"तस्बिरभित्र तस्बिर नामक मोडमा प्रविष्ट गर्नुहोस्"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"मिडियाका नियन्त्रणहरू देखाइएका छन्"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"मिडियाका नियन्त्रणहरूलाई लुकाइएको छ, देखाउनका लागि d-pad नामक बटन थिच्नुहोस्"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"पूरा गर्नुहोस्"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"जारी राख्नुहोस्"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"MediaPlayer को त्रुटिको कोड %1$d, यसको अतिरिक्त %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"सुरु गरौँ"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"अर्को"</string>
+</resources>
diff --git a/leanback/src/main/res/values-nl/strings.xml b/leanback/src/main/res/values-nl/strings.xml
new file mode 100644
index 0000000..a8157a6
--- /dev/null
+++ b/leanback/src/main/res/values-nl/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="8126335323963415494">"Navigatiemenu"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Actie zoeken"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Zoeken"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Spreek om te zoeken"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> zoeken"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Spreek om <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> te zoeken"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Afspelen"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Pauzeren"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Vooruitspoelen"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Vooruitspoelen %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Terugspoelen"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Terugspoelen %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Naar volgende"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Naar vorige"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Meer acties"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Selectie van \'Leuk\' ongedaan maken"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"\'Leuk\' selecteren"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Selectie van \'Niet leuk\' ongedaan maken"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"\'Niet leuk\' selecteren"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Niet herhalen"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Alles herhalen"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Eén herhalen"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Shuffle inschakelen"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Shuffle uitschakelen"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Hoge kwaliteit inschakelen"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Hoge kwaliteit uitschakelen"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Ondertiteling inschakelen"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Ondertiteling uitschakelen"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Scherm-in-scherm-modus openen"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Opties voor mediabediening worden weergegeven"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Opties voor mediabediening verborgen. Druk op de D-pad om ze weer te geven."</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Voltooien"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Doorgaan"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"Mediaspeler: foutcode %1$d extra %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"AAN DE SLAG"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Volgende"</string>
+</resources>
diff --git a/leanback/src/main/res/values-pa/strings.xml b/leanback/src/main/res/values-pa/strings.xml
new file mode 100644
index 0000000..fd08a54
--- /dev/null
+++ b/leanback/src/main/res/values-pa/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="8126335323963415494">"ਨੈਵੀਗੇਸ਼ਨ ਮੀਨੂ"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"ਖੋਜ ਕਾਰਵਾਈ"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"ਖੋਜੋ"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"ਖੋਜਣ ਲਈ ਬੋਲੋ"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> ਖੋਜੋ"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> ਖੋਜਣ ਲਈ ਬੋਲੋ"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"ਚਲਾਓ"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"ਰੋਕੋ"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"ਤੇਜ਼ੀ ਨਾਲ ਅੱਗੇ ਕਰੋ"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"%1$dX ਤੇਜ਼ੀ ਨਾਲ ਅੱਗੇ ਕਰੋ"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"ਪਿੱਛੇ ਕਰੋ"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"%1$dX ਪਿੱਛੇ ਕਰੋ"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"ਅਗਲੇ ਨੂੰ ਛੱਡੋ"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"ਪਿਛਲੇ ਨੂੰ ਛੱਡੋ"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"ਹੋਰ ਕਾਰਵਾਈਆਂ"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"ਸਲਾਹੋ ਨੂੰ ਅਣ-ਚੁਣਿਆ ਕਰੋ"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"ਸਲਾਹੋ ਨੂੰ ਚੁਣੋ"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"\'ਨਾ ਸਲਾਹੋ\' ਨੂੰ ਅਣ-ਚੁਣਿਆ ਕਰੋ"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"\'ਨਾ ਸਲਾਹੋ\' ਨੂੰ ਚੁਣੋ"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"ਕਿਸੇ ਨੂੰ ਨਾ ਦੁਹਰਾਓ"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"ਸਭ ਦੁਹਰਾਓ"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"ਇੱਕ ਨੂੰ ਦੁਹਰਾਓ"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"ਬੇਤਰਤੀਬ ਨੂੰ ਚਾਲੂ ਕਰੋ"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"ਬੇਤਰਤੀਬ ਨੂੰ ਬੰਦ ਕਰੋ"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"ਬਿਹਤਰੀਨ ਕੁਆਲਿਟੀ ਨੂੰ ਚਾਲੂ ਕਰੋ"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"ਬਿਹਤਰੀਨ ਕੁਆਲਿਟੀ ਨੂੰ ਬੰਦ ਕਰੋ"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"ਬੰਦ ਸੁਰਖੀਆਂ ਚਾਲੂ ਕਰੋ"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"ਬੰਦ ਸੁਰਖੀਆਂ ਬੰਦ ਕਰੋ"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"ਤਸਵੀਰ-ਵਿੱਚ-ਤਸਵੀਰ ਮੋਡ ਵਿੱਚ ਦਾਖਲ ਹੋਵੋ"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"ਮੀਡੀਆ ਕੰਟਰੋਲ ਦਿਖਾਏ ਗਏ"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"ਮੀਡੀਆ ਕੰਟਰੋਲ ਲੁਕੇ ਹੋਏ ਹਨ, ਦਿਖਾਉਣ ਲਈ ਡੀ-ਪੈਡ ਦਬਾਓ"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"ਪੂਰਾ ਕਰੋ"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"ਜਾਰੀ ਰੱਖੋ"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"MediaPlayer ਗੜਬੜ ਕੋਡ %1$d ਵਾਧੂ %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"ਸ਼ੁਰੂਆਤ ਕਰੋ"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"ਅੱਗੇ"</string>
+</resources>
diff --git a/leanback/src/main/res/values-pl/strings.xml b/leanback/src/main/res/values-pl/strings.xml
new file mode 100644
index 0000000..b679bdb
--- /dev/null
+++ b/leanback/src/main/res/values-pl/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="8126335323963415494">"Menu nawigacyjne"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Wyszukaj czynność"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Szukaj"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Powiedz, by wyszukać"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Szukaj: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Powiedz, by wyszukać: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Odtwórz"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Wstrzymaj"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Przewiń do przodu"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Przewiń do przodu %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Przewiń do tyłu"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Przewiń do tyłu %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Pomiń następny"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Pomiń poprzedni"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Więcej działań"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Odznacz Lubię"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Zaznacz Lubię"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Odznacz Nie lubię"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Zaznacz Nie lubię"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Nie powtarzaj"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Powtórz wszystko"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Powtórz jeden"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Włącz odtwarzanie losowe"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Wyłącz odtwarzanie losowe"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Włącz wysoką jakość"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Wyłącz wysoką jakość"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Włącz napisy"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Wyłącz napisy"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Włącz tryb obrazu w obrazie"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Elementy sterujące multimediami są wyświetlone"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Elementy sterujące multimediami są ukryte – naciśnij pad kierunkowy, by je wyświetlić"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Zakończ"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Dalej"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"MediaPlayer – kod błędu %1$d, dodatkowo %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"ROZPOCZNIJ"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Dalej"</string>
+</resources>
diff --git a/leanback/src/main/res/values-pt-rBR/strings.xml b/leanback/src/main/res/values-pt-rBR/strings.xml
new file mode 100644
index 0000000..01d56cb
--- /dev/null
+++ b/leanback/src/main/res/values-pt-rBR/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="8126335323963415494">"Menu de navegação"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Ação de pesquisa"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Pesquisar"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Fale para pesquisar"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Pesquisar <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Fale para pesquisar <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Reproduzir"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Pausar"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Avançar"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Avançar %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Retroceder"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Retroceder %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Pular próxima"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Pular anterior"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Mais ações"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Desmarcar gostei"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Marcar gostei"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Desmarcar não gostei"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Marcar não gostei"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Não repetir"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Repetir tudo"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Repetir um item"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Ativar reprodução aleatória"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Desativar reprodução aleatória"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Ativar alta qualidade"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Desativar alta qualidade"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Ativar closed captioning"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Desativar closed captioning"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Entrar no modo Picture in Picture"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Os controles de mídia estão sendo exibidos"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Os controles de mídia estão ocultos. Pressione o botão direcional para exibi-los"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Concluir"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Continuar"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"Código de erro do MediaPlayer %1$d extra %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"PRIMEIROS PASSOS"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Próxima"</string>
+</resources>
diff --git a/leanback/src/main/res/values-pt-rPT/strings.xml b/leanback/src/main/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..9b7d81c
--- /dev/null
+++ b/leanback/src/main/res/values-pt-rPT/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="8126335323963415494">"Menu de navegação"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Ação de pesquisa"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Pesquisar"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Falar para pesquisar"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Pesquisar <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Falar para pesquisar <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Reproduzir"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Interromper"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Avançar"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Avançar %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Recuar"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Recuar %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Avançar para o seguinte"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Avançar para o anterior"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Mais ações"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Desselecionar Gosto"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Selecionar Gosto"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Desselecionar Não gosto"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Selecionar Não gosto"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Não repetir"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Repetir tudo"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Repetir um"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Ativar reprodução aleatória"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Desativar reprodução aleatória"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Ativar alta qualidade"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Desativar alta qualidade"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Ativar legendas"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Desativar legendas"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Entrar no modo de ecrã no ecrã"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Controlos de multimédia apresentados"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Controlos de multimédia ocultados. Prima o teclado direcional para mostrar."</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Terminar"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Continuar"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"Código de erro do MediaPlayer %1$d extra %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"COMEÇAR A UTILIZAR"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Seguinte"</string>
+</resources>
diff --git a/leanback/src/main/res/values-pt/strings.xml b/leanback/src/main/res/values-pt/strings.xml
new file mode 100644
index 0000000..01d56cb
--- /dev/null
+++ b/leanback/src/main/res/values-pt/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="8126335323963415494">"Menu de navegação"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Ação de pesquisa"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Pesquisar"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Fale para pesquisar"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Pesquisar <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Fale para pesquisar <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Reproduzir"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Pausar"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Avançar"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Avançar %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Retroceder"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Retroceder %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Pular próxima"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Pular anterior"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Mais ações"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Desmarcar gostei"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Marcar gostei"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Desmarcar não gostei"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Marcar não gostei"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Não repetir"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Repetir tudo"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Repetir um item"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Ativar reprodução aleatória"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Desativar reprodução aleatória"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Ativar alta qualidade"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Desativar alta qualidade"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Ativar closed captioning"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Desativar closed captioning"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Entrar no modo Picture in Picture"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Os controles de mídia estão sendo exibidos"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Os controles de mídia estão ocultos. Pressione o botão direcional para exibi-los"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Concluir"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Continuar"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"Código de erro do MediaPlayer %1$d extra %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"PRIMEIROS PASSOS"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Próxima"</string>
+</resources>
diff --git a/leanback/src/main/res/values-ro/strings.xml b/leanback/src/main/res/values-ro/strings.xml
new file mode 100644
index 0000000..22055b3
--- /dev/null
+++ b/leanback/src/main/res/values-ro/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="8126335323963415494">"Meniu de navigare"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Acțiunea de căutare"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Căutați"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Rostiți pentru a căuta"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Căutați <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Rostiți pentru a căuta <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Redați"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Întrerupeți"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Derulați rapid înainte"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Derulați rapid înainte cu %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Derulați înapoi"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Derulați înapoi cu %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Ignorați articolul următor"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Ignorați articolul anterior"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Mai multe acțiuni"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Deselectați „Îmi place”"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Selectați „Îmi place”"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Deselectați „Nu îmi place”"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Selectați „Nu îmi place”"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Nu repetați"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Repetați toate"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Repetați unul"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Activați redarea în mod aleatoriu"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Dezactivați redarea în mod aleatoriu"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Activați calitatea înaltă"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Dezactivați calitatea înaltă"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Activați subtitrările"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Dezactivați subtitrările"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Activați modul Picture-in-Picture"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Comenzile media sunt afișate"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Comenzile media sunt ascunse. Apăsați pe butonul direcțional pentru a le afișa."</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Finalizați"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Continuați"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"Cod de eroare MediaPlayer %1$d suplimentar %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"ÎNCEPEȚI"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Înainte"</string>
+</resources>
diff --git a/leanback/src/main/res/values-ru/strings.xml b/leanback/src/main/res/values-ru/strings.xml
new file mode 100644
index 0000000..20ae724
--- /dev/null
+++ b/leanback/src/main/res/values-ru/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="8126335323963415494">"Меню навигации"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Поиск"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Поиск"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Произнесите запрос"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Искать здесь: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Произнесите запрос для поиска здесь: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Воспроизвести"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Пауза"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Перемотать вперед"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Перемотать вперед %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Перемотать назад"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Перемотать назад %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Перейти к следующему аудиофайлу"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Перейти к предыдущему аудиофайлу"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Дополнительно"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Снять отметку Нравится"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Поставить отметку Нравится"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Снять отметку Не нравится"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Поставить отметку Не нравится"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Не повторять"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Повторять все"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Повторять этот аудиофайл"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Включить перемешивание"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Отключить перемешивание"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Включить высокое качество"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Отключить высокое качество"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Включить субтитры"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Отключить субтитры"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Включить режим Картинка в картинке"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Элементы управления показаны"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Элементы управления скрыты. Чтобы открыть их, нажмите D-pad"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Готово"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Далее"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"Код ошибки медиапроигрывателя: %1$d (дополнительный: %2$d)"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"НАЧАТЬ"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Далее"</string>
+</resources>
diff --git a/leanback/src/main/res/values-si/strings.xml b/leanback/src/main/res/values-si/strings.xml
new file mode 100644
index 0000000..efb0307
--- /dev/null
+++ b/leanback/src/main/res/values-si/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="8126335323963415494">"සංචාලන මෙනුව"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"සෙවීමේ ක්‍රියාව"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"සෙවීම"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"සෙවීමට කථා කරන්න"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> සොයන්න"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> සොයන්න කථා කරන්න"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"වාදනය"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"විරාම කරන්න"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"වේගයෙන් ඉදිරියට යන"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"%1$dX වේගයෙන් ඉදිරියට යවන්න"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"ආපස්සට යවන්න"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"%1$dX ආපස්සට යවන්න"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"ඊළඟ එක මග අරින්න"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"කළින් එක මග අරින්න"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"තව ක්‍රියාකාරකම්"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"මහපටැඟිල්ල ඉහළට තිබීම තේරීම නොකරන්න"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"මහපටැඟිල්ල ඉහළට තිබීම තේරීම කරන්න"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"මහපටැඟිල්ල පහළට තිබීම තේරීම නොකරන්න"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"මහපටැඟිල්ල පහළට තිබීම තේරීම කරන්න"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"නැවත කරන්න කිසිවක් නැත"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"සියල්ල නැවත කරන්න"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"එකක් නැවත කරන්න"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"ඇනීම සබල කරන්න"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"ඇනීම අබල කරන්න"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"උපරිම ගුණත්වය සබල කරන්න"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"උපරිම ගුණත්වය අබල කරන්න"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"වැසුණු ශිර්ෂ කිරීම සබල කරන ලදි"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"වැසුණු ශිර්ෂ කිරීම අබල කරන ලදි"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"පින්තූරය-තුළ-පින්තූරය ප්‍රකාරයට ඇතුළු වන්න"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"මාධ්‍ය පාලක පෙන්වා ඇත"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"මාධ්‍ය පාලක සඟවා ඇත, පෙන්වීමට ඩී-පෑඩ් ඔබන්න"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"අවසන් කරන්න"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"ඉදිරියට යන්න"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"MediaPlayer දෝෂ කේතය %1$d අමතර %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"පටන් ගන්න"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"ඊළඟ"</string>
+</resources>
diff --git a/leanback/src/main/res/values-sk/strings.xml b/leanback/src/main/res/values-sk/strings.xml
new file mode 100644
index 0000000..7774f88
--- /dev/null
+++ b/leanback/src/main/res/values-sk/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="8126335323963415494">"Navigačná ponuka"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Akcia vyhľadávania"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Hľadať"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Hovorením spustíte vyhľadávanie"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Vyhľadať výraz <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Vyslovením výrazu <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> spustíte jeho vyhľad."</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Prehrať"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Pozastaviť"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Pretočiť dopredu"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Pretočiť dopredu %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Pretočiť späť"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Pretočiť späť %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Prejsť na ďalšiu položku"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Prejsť na predchádzajúcu položku"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Ďalšie akcie"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Zrušiť Páči sa mi"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Vybrať Páči sa mi"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Zrušiť Nepáči sa mi"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Vybrať Nepáči sa mi"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Neopakovať"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Opakovať všetko"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Opakovať jednu položku"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Zapnúť náhodné prehrávanie"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Vypnúť náhodné prehrávanie"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Povoliť médiá vo vysokej kvalite"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Zakázať médiá vo vysokej kvalite"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Zapnúť skryté titulky"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Vypnúť skryté titulky"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Prejsť do režimu obraz v obraze"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Ovládacie prvky médií sa zobrazujú"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Ovládacie prvky médií sú skryté, zobrazíte ich stlačením krížového ovládača"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Dokončiť"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Pokračovať"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"Kód chyby MediaPlayer %1$d extra %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"ZAČÍNAME"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Ďalej"</string>
+</resources>
diff --git a/leanback/src/main/res/values-sl/strings.xml b/leanback/src/main/res/values-sl/strings.xml
new file mode 100644
index 0000000..a0ac300
--- /dev/null
+++ b/leanback/src/main/res/values-sl/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="8126335323963415494">"Meni za krmarjenje"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Dejanje iskanja"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Iskanje"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Izgovorite iskalno poizvedbo"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Iskanje: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Izgovorite poizvedbo za iskanje v <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$d-kratno"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$d-kratno"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Predvajaj"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Začasno ustavi"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Previj naprej"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Hitro previjanje naprej – %1$d-kratno"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Previj nazaj"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Previjanje nazaj – %1$d-kratno"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Preskoči na naslednjega"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Preskoči na prejšnjega"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Več dejanj"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Prekliči izbor palca gor"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Izberi palec gor"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Prekliči izbor palca dol"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Izberi palec dol"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Brez ponavljanja"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Ponovi vse"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Ponovi eno"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Omogoči naključno predvajanje"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Onemogoči naključno predvajanje"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Omogoči visoko kakovost"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Onemogoči visoko kakovost"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Omogoči podnapise"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Onemogoči podnapise"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Vklop načina za sliko v sliki"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Kontrolniki predstavnosti so prikazani"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Kontrolniki predstavnosti so skriti, za prikaz pritisnite smerni gumb"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Dokončaj"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Nadaljuj"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"Koda napake MediaPlayerja: %1$d, dodatno %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"ZAČNITE"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Naprej"</string>
+</resources>
diff --git a/leanback/src/main/res/values-sq/strings.xml b/leanback/src/main/res/values-sq/strings.xml
new file mode 100644
index 0000000..00b42ad
--- /dev/null
+++ b/leanback/src/main/res/values-sq/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="8126335323963415494">"Menyja e navigimit"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Veprimi i kërkimit"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Kërko"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Fol për të kërkuar"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Kërko për <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Fol për të kërkuar <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Luaj"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Pauzë"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Përparo me shpejtësi"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Përparo me shpejtësi %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Rikthe"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Kthe në fillim %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Kapërce për te tjetra"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Kapërce të mëparshmin"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Veprime të tjera"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Hiq nga përzgjedhja \"Gishti lart\""</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Përzgjidh \"Gishtin sipër\""</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Hiq nga përzgjedhja \"Gishti poshtë\""</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Përzgjidh \"Gishtin poshtë\""</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Mos përsërit asnjë"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Përsërit të gjitha"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Përsërit një"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Aktivizo përzierjen"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Çaktivizo përzierjen"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Aktivizo \"Cilësinë e lartë\""</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Çaktivizo \"Cilësinë e lartë\""</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Aktivizo titrat"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Çaktivizo titrat me sekuencë kohore"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Aktivizo modalitetin e figurës brenda figurës"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Kontrollet e medias të shfaqura"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Kontrollet e medias të fshehura, shtyp bllokun e drejtimit për t\'i shfaqur"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Përfundo"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Vazhdo"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"Kodi i gabimit i MediaPlayer %1$d shtesa %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"FILLO"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Para"</string>
+</resources>
diff --git a/leanback/src/main/res/values-sr/strings.xml b/leanback/src/main/res/values-sr/strings.xml
new file mode 100644
index 0000000..5a64fca
--- /dev/null
+++ b/leanback/src/main/res/values-sr/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="8126335323963415494">"Мени за навигацију"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Радња претраге"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Претражите"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Изговорите да бисте претраживали"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Претражите <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Изговорите да бисте претражили <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Пусти"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Паузирај"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Премотај унапред"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Премотај унапред %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Премотај уназад"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Премотај уназад %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Прескочи на следеће"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Прескочи на претходно"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Још радњи"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Опозови избор „Свиђа ми се“"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Изабери „Свиђа ми се“"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Опозови избор „Не свиђа ми се“"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Изабери „Не свиђа ми се“"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Не понављај ниједну"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Понови све"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Понови једну"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Омогући насумично пуштање"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Онемогући насумично пуштање"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Омогући висок квалитет"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Онемогући висок квалитет"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Омогући титлове"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Онемогући титлове"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Уђи у режим Слика у слици"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Контроле за медије су приказане"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Контроле за медије су скривене, притисните d-pad да бисте их приказали"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Заврши"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Настави"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"Кôд грешке MediaPlayer-а: %1$d, додатно %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"ЗАПОЧНИТЕ"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Даље"</string>
+</resources>
diff --git a/leanback/src/main/res/values-sv/strings.xml b/leanback/src/main/res/values-sv/strings.xml
new file mode 100644
index 0000000..38c8112
--- /dev/null
+++ b/leanback/src/main/res/values-sv/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="8126335323963415494">"Navigeringsmeny"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Sökåtgärd"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Sök"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Säg det du söker efter"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Sök i <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Tala för att söka i <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Spela upp"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Pausa"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Snabbspola framåt"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Spola framåt %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Spola tillbaka"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Spola tillbaka %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Hoppa till nästa"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Hoppa till föregående"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Fler åtgärder"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Avmarkera tummen upp"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Markera tummen upp"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Avmarkera tummen ned"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Markera tummen ned"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Upprepa inga"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Upprepa alla"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Upprepa en"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Blanda spår"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Blanda inte spår"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Aktivera hög kvalitet"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Inaktivera hög kvalitet"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Aktivera textning"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Inaktivera textning"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Aktivera läget Bild-i-bild"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Mediakontrollerna visas"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Mediakontrollerna är dolda och visas om du trycker på styrkorset"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Slutför"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Fortsätt"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"Felkod %1$d för MediaPlayer, extra %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"KOM IGÅNG"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Nästa"</string>
+</resources>
diff --git a/leanback/src/main/res/values-sw/strings.xml b/leanback/src/main/res/values-sw/strings.xml
new file mode 100644
index 0000000..167a9b6
--- /dev/null
+++ b/leanback/src/main/res/values-sw/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="8126335323963415494">"Menyu ya kusogeza"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Kitendo cha Kutafuta"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Tafuta"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Tamka ili utafute"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Tafuta <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Tamka ili utafute <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"X%1$d"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"X%1$d"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Cheza"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Sitisha"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Sogeza Mbele Haraka"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Sogeza Mbele X%1$d"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Rudisha nyuma"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Rudisha nyuma X%1$d"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Nenda kwenye Inayofuata"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Nenda kwenye Iliyotangulia"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Vitendo zaidi"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Acha Kuchagua \'Bomba\'"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Chagua \'Bomba\'"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Acha kuchagua \'Hainipendezi\'"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Chagua \'Hainipendezi\'"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Usirudie Yoyote"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Rudia Zote"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Rudia Moja"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Washa Kipengele cha Kuchanganya"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Zima Kipengele cha Kuchanganya"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Washa Ubora wa Juu"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Zima Ubora wa Juu"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Washa Manukuu"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Zima Manukuu"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Weka Hali ya Picha ndani ya Picha"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Inaonyesha udhibiti wa maudhui"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Imeficha udhibiti wa maudhui, bonyeza d-pad ili uuonyeshe"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Maliza"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Endelea"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"Msimbo wa hitilafu wa Kichezaji Maudhui %1$d %2$d za ziada"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"ANZA"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Endelea"</string>
+</resources>
diff --git a/leanback/src/main/res/values-ta/strings.xml b/leanback/src/main/res/values-ta/strings.xml
new file mode 100644
index 0000000..10c84ca
--- /dev/null
+++ b/leanback/src/main/res/values-ta/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="8126335323963415494">"வழிசெலுத்தல் மெனு"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"தேடல் செயல்"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"தேடுக"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"தேட, பேசவும்"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>ஐத் தேடுக"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>ஐத் தேட, பேசவும்"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"இயக்கு"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"இடைநிறுத்து"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"வேகமாக முன்செல்"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"%1$dX வேகத்தில் முன்செல்"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"பின்செல்"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"%1$dX வேகத்தில் பின்செல்"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"அடுத்ததைத் தவிர்"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"முந்தையதைத் தவிர்"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"மேலும் செயல்கள்"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"பிடித்திருக்கிறது என்பதைத் தேர்வுநீக்கு"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"பிடித்திருக்கிறது என்பதைத் தேர்ந்தெடு"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"பிடிக்கவில்லை என்பதைத் தேர்வுநீக்கு"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"பிடிக்கவில்லை என்பதைத் தேர்ந்தெடு"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"எதையும் மீண்டும் இயக்காதே"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"அனைத்தையும் மீண்டும் இயக்கு"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"ஒன்றை மட்டும் மீண்டும் இயக்கு"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"கலைத்து இயக்கு"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"கலைக்காமல் இயக்கு"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"உயர்தரத்தை இயக்கு"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"உயர்தரத்தை முடக்கு"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"விரிவான வசனங்களை இயக்கு"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"விரிவான வசனங்களை முடக்கு"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"பிக்ச்சர்-இன்-பிக்ச்சர் பயன்முறைக்குச் செல்"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"மீடியா கட்டுப்பாடுகள் காட்டப்படுகின்றன"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"மீடியா கட்டுப்பாடுகள் மறைக்கப்பட்டுள்ளன. கட்டுப்பாடுகளைக் காட்ட, டி பேடை அழுத்தவும்"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"முடி"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"தொடர்க"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"MediaPlayer பிழைக் குறியீடு: %1$d கூடுதல் குறியீடு %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"தொடங்குக"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"அடுத்த பக்கத்திற்குச் செல்லும்"</string>
+</resources>
diff --git a/leanback/src/main/res/values-te/strings.xml b/leanback/src/main/res/values-te/strings.xml
new file mode 100644
index 0000000..312b570
--- /dev/null
+++ b/leanback/src/main/res/values-te/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="8126335323963415494">"నావిగేషన్ మెను"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"శోధన చర్య"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"శోధన"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"శోధించడానికి మాటల ద్వారా చెప్పండి"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>ని శోధించండి"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>లో శోధించడానికి మాటల ద్వారా చెప్పండి"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"ప్లే చేయి"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"పాజ్ చేయి"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"వేగంగా ఫార్వార్డ్ చేయి"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"%1$dX ఫాస్ట్ ఫార్వార్డ్ చేయి"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"రివైండ్ చేయి"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"%1$dX రివైండ్ చేయి"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"తదుపరి దానికి దాటవేయి"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"మునుపటి దానికి దాటవేయి"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"మరిన్ని చర్యలు"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"బాగుంది సంకేతాన్ని తీసివేయి"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"బాగుంది సంకేతాన్ని ఎంపిక చేయి"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"బాగాలేదు సంకేతాన్ని తీసివేయి"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"బాగాలేదు సంకేతాన్ని ఎంపిక చేయి"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"ఏదీ పునరావృతం చేయవద్దు"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"అన్నీ పునరావృతం చేయి"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"ఒకదాన్ని పునరావృతం చేయి"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"షఫుల్ చేయడాన్ని ప్రారంభించు"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"షఫుల్ చేయడాన్ని నిలిపివేయి"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"అధిక నాణ్యతను ప్రారంభించు"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"అధిక నాణ్యతను నిలిపివేయి"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"మూసివేసిన శీర్షికలను ప్రారంభించు"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"మూసివేసిన శీర్షికలను నిలిపివేయి"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"చిత్రంలో చిత్రం మోడ్‌లోకి ప్రవేశించు"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"మీడియా నియంత్రణలు చూపబడ్డాయి"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"మీడియా నియంత్రణలు దాచబడ్డాయి, చూపించడానికి d-ప్యాడ్ నొక్కండి"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"ముగించండి"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"కొనసాగించండి"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"MediaPlayer ఎర్రర్ కోడ్ %1$d అదనంగా %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"ప్రారంభించు"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"తదుపరి"</string>
+</resources>
diff --git a/leanback/src/main/res/values-th/strings.xml b/leanback/src/main/res/values-th/strings.xml
new file mode 100644
index 0000000..b90381c
--- /dev/null
+++ b/leanback/src/main/res/values-th/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="8126335323963415494">"เมนูการนำทาง"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"การดำเนินการค้นหา"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"ค้นหา"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"พูดเพื่อค้นหา"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"ค้นหา <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"พูดเพื่อค้นหา <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"เล่น"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"หยุดชั่วคราว"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"กรอไปข้างหน้า"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"กรอไปข้างหน้า %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"กรอกลับ"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"กรอกลับ %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"ข้ามไปรายการถัดไป"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"ข้ามไปรายการก่อนหน้า"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"การดำเนินการเพิ่มเติม"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"ยกเลิกการเลือกว่าชอบ"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"เลือกว่าชอบ"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"ยกเลิกการเลือกว่าไม่ชอบ"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"เลือกว่าไม่ชอบ"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"ไม่เล่นซ้ำ"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"เล่นซ้ำทั้งหมด"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"เล่นซ้ำรายการเดียว"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"เปิดใช้การสุ่มเพลง"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"ปิดใช้การสุ่มเพลง"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"เปิดใช้คุณภาพสูง"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"ปิดใช้คุณภาพสูง"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"เปิดใช้คำอธิบายภาพ"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"ปิดใช้คำอธิบายภาพ"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"เข้าสู่โหมดการแสดงภาพซ้อนภาพ"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"แสดงการควบคุมสื่ออยู่"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"ซ่อนการควบคุมสื่ออยู่ กด D-pad เพื่อแสดง"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"เสร็จสิ้น"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"ต่อไป"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"รหัสข้อผิดพลาด MediaPlayer %1$d เพิ่มเติม %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"เริ่มต้น"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"ถัดไป"</string>
+</resources>
diff --git a/leanback/src/main/res/values-tl/strings.xml b/leanback/src/main/res/values-tl/strings.xml
new file mode 100644
index 0000000..8396af8
--- /dev/null
+++ b/leanback/src/main/res/values-tl/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="8126335323963415494">"Menu sa pag-navigate"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Pagkilos sa Paghahanap"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Maghanap"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Magsalita upang maghanap"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Hanapin ang <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Magsalita upang hanapin ang <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"I-play"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"I-pause"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"I-fast Forward"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"I-fast Forward nang %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"I-rewind"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"I-rewind nang %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Laktawan ang Susunod"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Laktawan ang Nakaraan"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Mas Marami Pang Pagkilos"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Alisin sa Pagkakapili ang Thumb Up"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Piliin ang Thumb Up"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Alisin sa Pagkakapili ang Thumb Down"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Piliin ang Thumb Down"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Walang Uulitin"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Ulitin Lahat"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Ulitin ang Isa"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"I-enable ang Pag-shuffle"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"I-disable ang Pag-shuffle"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"I-enable ang Mataas na Kalidad"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"I-disable ang Mataas na Kalidad"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"I-enable ang Closed Captioning"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"I-disable ang Closed Captioning"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Pumasok sa Picture-In-Picture Mode"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Ipinapakita ang mga kontrol ng media"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Nakatago ang mga kontrol ng media, pindutin ang d-pad upang ipakita"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Tapusin"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Magpatuloy"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"Code ng error na %1$d ng MediaPlayer na may extra na %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"MAGSIMULA"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Susunod"</string>
+</resources>
diff --git a/leanback/src/main/res/values-tr/strings.xml b/leanback/src/main/res/values-tr/strings.xml
new file mode 100644
index 0000000..ec3dee7
--- /dev/null
+++ b/leanback/src/main/res/values-tr/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="8126335323963415494">"Gezinme menüsü"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Arama İşlemi"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Arama yapın"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Arama yapmak için konuşun"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> araması yapın"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> araması yapmak için konuşun"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Oynat"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Duraklat"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"İleri Sar"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"%1$dX İleri Sar"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Geri Sar"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"%1$dX Geri Sar"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Sonrakine Atla"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Öncekine Atla"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Diğer İşlemler"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Beğenme Seçimini Kaldır"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Beğenmeyi Seç"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Beğenmeme Seçimini Kaldır"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Beğenmemeyi Seç"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Hiçbirini Tekrarlama"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Tümünü Tekrarla"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Birini Tekrarla"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Karıştırmayı Etkinleştir"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Karıştırmayı Devre Dışı Bırak"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Yüksek Kalitede Oynatmayı Etkinleştir"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Yüksek Kalitede Oynatmayı Devre Dışı Bırak"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Altyazıları Etkinleştir"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Altyazıları Devre Dışı Bırak"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Pencere İçinde Pencere Moduna Geç"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Medya denetimleri gösteriliyor"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Medya denetimleri gizli durumda. Görüntülemek için d-pad\'e basın."</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Son"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Devam"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"MediaPlayer hata kodu %1$d ekstra %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"BAŞLA"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Sonraki"</string>
+</resources>
diff --git a/leanback/src/main/res/values-uk/strings.xml b/leanback/src/main/res/values-uk/strings.xml
new file mode 100644
index 0000000..ce472f4
--- /dev/null
+++ b/leanback/src/main/res/values-uk/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="8126335323963415494">"Меню навігації"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Команда пошуку"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Пошук"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Продиктуйте пошуковий запит"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Шукати: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Продиктуйте, щоб шукати: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Відтворити"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Призупинити"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Перемотати вперед"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Перемотати вперед – %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Перемотати назад"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Перемотати назад – %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Пропустити наступний елемент"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Пропустити попередній елемент"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Більше команд"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Не вибирати оцінку \"Подобається\""</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Вибрати оцінку \"Подобається\""</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Не вибирати оцінку \"Не подобається\""</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Вибрати оцінку \"Не подобається\""</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Не повторювати"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Повторити все"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Повторити один елемент"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Увімкнути перемішування"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Вимкнути перемішування"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Увімкнути високу якість"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Вимкнути високу якість"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Увімкнути субтитри"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Вимкнути субтитри"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Перейти в режим \"Картинка в картинці\""</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Елементи керування медіа показано"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Елементи керування медіа сховано. Натисніть цифрову панель, щоб показати їх"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Готово"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Продовжити"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"Код помилки MediaPlayer: %1$d extra %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"ПОЧАТИ"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Далі"</string>
+</resources>
diff --git a/leanback/src/main/res/values-ur/strings.xml b/leanback/src/main/res/values-ur/strings.xml
new file mode 100644
index 0000000..74bec7c
--- /dev/null
+++ b/leanback/src/main/res/values-ur/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="8126335323963415494">"نیویگیشن مینو"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"تلاش کی کارروائی"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"تلاش کریں"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"تلاش کرنے کیلئے بولیں"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> تلاش کریں"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> تلاش کرنے کیلئے بولیں"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"چلائیں"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"موقوف کریں"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"تیزی سے فارورڈ کریں"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"‏تیزی سے فارورڈ کریں ‎%1$dX‎"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"ریوائینڈ کریں"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"‏ریوائینڈ کریں ‎%1$dX‎"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"اگلے پر جائیں"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"پچھلے پر جائیں"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"مزید کارروائیاں"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"اوپر کی طرف والے انگوٹھے کے نشان کو غیر منتخب کریں"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"اوپر کی طرف والے انگوٹھے کے نشان کو منتخب کریں"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"نیچے کی طرف والے انگوٹھے کے نشان کو غیر منتخب کریں"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"نیچے کی طرف والے انگوٹھے کے نشان کو منتخب کریں"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"کسی کو نہ دہرائیں"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"سبھی کو دہرائیں"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"ایک کو دہرائیں"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"شفل فعال کریں"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"شفل غیر فعال کریں"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"اعلی معیار فعال کریں"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"اعلی معیار غیر فعال کریں"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"سب ٹائٹلز فعال کریں"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"سب ٹائٹلز غیر فعال کریں"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"\'تصویر میں تصویر موڈ\' میں داخل ہوں"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"میڈیا کنٹرولز عیاں ہیں"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"‏میڈیا کنٹرولز مخفی ہیں، دکھانے کیلئے d-pad دبائیں"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"مکمل کریں"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"جاری رکھیں"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"‏MediaPlayer کی خرابی کا کوڈ %1$d اضافی %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"شروع کریں"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"آگے"</string>
+</resources>
diff --git a/leanback/src/main/res/values-uz/strings.xml b/leanback/src/main/res/values-uz/strings.xml
new file mode 100644
index 0000000..50a86af
--- /dev/null
+++ b/leanback/src/main/res/values-uz/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="8126335323963415494">"Navigatsiya menyusi"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Qidiruv amali"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Qidiruv"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Qidirish uchun gapiring"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Qidirish: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Qidirish uchun ayting: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Ijro"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Pauza"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Oldinga o‘tkazish"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"%1$dX tezlikda oldinga o‘tkazish"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Orqaga qaytarish"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"%1$dX tezlikda orqaga qaytarish"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Keyingisiga o‘tish"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Avvalgisiga qaytish"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Boshqa amallar"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Ijobiy baho tanlovini bekor qilish"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Ijobiy bahoni tanlash"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Salbiy baho tanlovini bekor qilish"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Salbiy bahoni tanlash"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Takrorlamaslik"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Barchasini takrorlash"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Bir marta takrorlash"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Aralashtirish funksiyasini yoqish"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Aralashtirish funksiyasini o‘chirish"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Yuqori sifatni yoqish"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Yuqori sifatni o‘chirib qo‘yish"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Taglavhalarni yoqish"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Taglavhalarni o‘chirib qo‘yish"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Tasvir ustida tasvir rejimiga kirish"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Boshqaruv elementlari ochiq"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Boshqaruv elementlari berkitilgan, ochish uchun D-pad tugmasini bosing"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Tayyor"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Keyingisi"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"Media pleyer xatoligi kodi: %1$d (yana: %2$d)"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"BOSHLASH"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Keyingisi"</string>
+</resources>
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/src/main/res/values-vi/strings.xml b/leanback/src/main/res/values-vi/strings.xml
new file mode 100644
index 0000000..3d23a41
--- /dev/null
+++ b/leanback/src/main/res/values-vi/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="8126335323963415494">"Menu điều hướng"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Tác vụ tìm kiếm"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Tìm kiếm"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Nói để tìm kiếm"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Tìm kiếm <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Nói để tìm kiếm <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Phát"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Tạm dừng"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Tua đi"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Tua đi %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Tua lại"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Tua lại %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Chuyển đến mục tiếp theo"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Chuyển về mục trước"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Tác vụ khác"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Bỏ chọn thích"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Chọn thích"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Bỏ chọn không thích"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Chọn không thích"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Không lặp lại"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Lặp lại tất cả"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Lặp lại một mục"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Bật phát ngẫu nhiên"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Tắt phát ngẫu nhiên"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Bật chế độ chất lượng cao"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Tắt chế độ chất lượng cao"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Bật phụ đề"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Tắt phụ đề"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Vào chế độ hình trong hình"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Điều khiển phương tiện được hiển thị"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Điều khiển phương tiện bị ẩn, nhấn d-pad để hiển thị"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Hoàn tất"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Tiếp tục"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"Mã lỗi MediaPlayer %1$d %2$d bổ sung"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"BẮT ĐẦU"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Tiếp"</string>
+</resources>
diff --git a/leanback/src/main/res/values-zh-rCN/strings.xml b/leanback/src/main/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..9ba86b4
--- /dev/null
+++ b/leanback/src/main/res/values-zh-rCN/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="8126335323963415494">"导航菜单"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"搜索操作"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"搜索"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"说话即可开始搜索"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"搜索<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"说话即可在<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>中搜索"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$d 倍速"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$d 倍速"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"播放"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"暂停"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"快进"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"%1$d 倍速快进"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"快退"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"%1$d 倍速快退"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"跳至下一个"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"跳至上一个"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"更多操作"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"取消选择顶操作"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"选择顶操作"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"取消选择踩操作"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"选择踩操作"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"不重复播放"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"重复播放全部"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"重复播放一项"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"开启随机播放"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"关闭随机播放"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"开启高画质模式"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"关闭高画质模式"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"开启字幕"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"关闭字幕"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"进入画中画模式"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"媒体控件已显示"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"媒体控件已隐藏,按方向键即可显示"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"完成"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"继续"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"MediaPlayer 错误代码:%1$d extra %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"开始"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"继续"</string>
+</resources>
diff --git a/leanback/src/main/res/values-zh-rHK/strings.xml b/leanback/src/main/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..22894c0
--- /dev/null
+++ b/leanback/src/main/res/values-zh-rHK/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="8126335323963415494">"導覽選單"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"搜尋操作"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"搜尋"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"使用語音搜尋"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"搜尋「<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>」"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"使用語音搜尋「<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>」"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"播放"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"暫停"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"向前快轉"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"快轉 %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"倒轉"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"倒轉 %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"跳去下一個項目"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"跳去上一個項目"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"更多操作"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"取消揀鍾意"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"揀鍾意"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"取消揀唔鍾意"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"揀唔鍾意"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"唔重複播放"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"重複播放所有項目"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"重複播放單一項目"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"啟用隨機播放"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"停用隨機播放"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"啟用高畫質播放"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"停用高畫質播放"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"啟用隱藏式字幕"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"停用隱藏式字幕"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"進入「畫中畫模式」"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"媒體控制項已顯示"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"媒體控制項已隱藏,按十字鍵即可顯示"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"完成"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"繼續"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"MediaPlayer 錯誤代碼:%1$d extra %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"開始使用"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"繼續"</string>
+</resources>
diff --git a/leanback/src/main/res/values-zh-rTW/strings.xml b/leanback/src/main/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..bcaf11e
--- /dev/null
+++ b/leanback/src/main/res/values-zh-rTW/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="8126335323963415494">"導覽選單"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"搜尋動作"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"搜尋"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"使用語音搜尋"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"搜尋「<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>」"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"使用語音搜尋「<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>」"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"播放"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"暫停"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"快轉"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"快轉 %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"倒轉"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"倒轉 %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"跳至下一個項目"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"跳至上一個項目"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"更多動作"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"取消選取喜歡"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"選取喜歡"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"取消選取不喜歡"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"選取不喜歡"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"不重複播放"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"重複播放所有項目"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"重複播放單一項目"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"啟用隨機播放"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"停用隨機播放"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"啟用高品質播放"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"停用高品質播放"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"啟用隱藏式輔助字幕"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"停用隱藏式輔助字幕"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"進入子母畫面模式"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"媒體控制項已顯示"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"媒體控制項已隱藏,按下 D-Pad 即可顯示"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"完成"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"繼續"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"MediaPlayer 錯誤代碼:%1$d extra %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"開始使用"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"繼續"</string>
+</resources>
diff --git a/leanback/src/main/res/values-zu/strings.xml b/leanback/src/main/res/values-zu/strings.xml
new file mode 100644
index 0000000..6f65904
--- /dev/null
+++ b/leanback/src/main/res/values-zu/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="8126335323963415494">"Imenyu yokuzulazula"</string>
+    <string name="orb_search_action" msgid="7534843523462177008">"Isenzo sokusesha"</string>
+    <string name="lb_search_bar_hint" msgid="4819380969103509861">"Sesha"</string>
+    <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Khuluma ukuze useshe"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Sesha i-<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Khuluma ukuze useshe i-<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"Dlala"</string>
+    <string name="lb_playback_controls_pause" msgid="1769131316742618433">"Misa isikhashana"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"Iya phambili ngokushesha"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"Hambisa phambili ngokushesha i-%1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Buyisela emuva"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Mikisa emuva i-%1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Yeqa okulandelayo"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Yeqa kwangaphambilini"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Izenzo eziningi"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Susa ukukhetha isithupha saphezulu"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Khetha okushaphu"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Susa ukukhetha isithupha saphansi"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Khetha isithupha saphansi"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Ungaphindi lutho"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Phinda konke"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Phida okukodwa"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Nika amandla ukushova"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Khubaza ukushova"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Nika amandla ikhwalithi ephezulu"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Khubaza ikhwalithi ephezulu"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Nika amandla ukwenza amazwibela okuvaliwe"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Khubaza ukwenza amazwibela okuvaliwe"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Ngena kumodi yesithombe esikusithombe"</string>
+    <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Izilawuli zemidiya zibonisiwe"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Izilawuli zemidiya zifihliwe, cindezela ku-d-pad ukuze uzibonise"</string>
+    <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Qeda"</string>
+    <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Qhubeka"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"Ikhodi yephutha ye-MediaPlayer engu-%1$d okungeziwe okungu-%2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="7674487829030291492">"QALISA"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Okulandelayo"</string>
+</resources>
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/main/java/android/arch/lifecycle/ViewModelProviders.java b/lifecycle/extensions/src/main/java/android/arch/lifecycle/ViewModelProviders.java
index d9894a8..0940235 100644
--- a/lifecycle/extensions/src/main/java/android/arch/lifecycle/ViewModelProviders.java
+++ b/lifecycle/extensions/src/main/java/android/arch/lifecycle/ViewModelProviders.java
@@ -21,6 +21,7 @@
 import android.arch.lifecycle.ViewModelProvider.Factory;
 import android.support.annotation.MainThread;
 import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
 import android.support.v4.app.Fragment;
 import android.support.v4.app.FragmentActivity;
 
@@ -65,10 +66,7 @@
     @NonNull
     @MainThread
     public static ViewModelProvider of(@NonNull Fragment fragment) {
-        ViewModelProvider.AndroidViewModelFactory factory =
-                ViewModelProvider.AndroidViewModelFactory.getInstance(
-                        checkApplication(checkActivity(fragment)));
-        return new ViewModelProvider(ViewModelStores.of(fragment), factory);
+        return of(fragment, null);
     }
 
     /**
@@ -83,10 +81,7 @@
     @NonNull
     @MainThread
     public static ViewModelProvider of(@NonNull FragmentActivity activity) {
-        ViewModelProvider.AndroidViewModelFactory factory =
-                ViewModelProvider.AndroidViewModelFactory.getInstance(
-                        checkApplication(activity));
-        return new ViewModelProvider(ViewModelStores.of(activity), factory);
+        return of(activity, null);
     }
 
     /**
@@ -101,8 +96,11 @@
      */
     @NonNull
     @MainThread
-    public static ViewModelProvider of(@NonNull Fragment fragment, @NonNull Factory factory) {
-        checkApplication(checkActivity(fragment));
+    public static ViewModelProvider of(@NonNull Fragment fragment, @Nullable Factory factory) {
+        Application application = checkApplication(checkActivity(fragment));
+        if (factory == null) {
+            factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
+        }
         return new ViewModelProvider(ViewModelStores.of(fragment), factory);
     }
 
@@ -119,8 +117,11 @@
     @NonNull
     @MainThread
     public static ViewModelProvider of(@NonNull FragmentActivity activity,
-            @NonNull Factory factory) {
-        checkApplication(activity);
+            @Nullable Factory factory) {
+        Application application = checkApplication(activity);
+        if (factory == null) {
+            factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
+        }
         return new ViewModelProvider(ViewModelStores.of(activity), factory);
     }
 
diff --git a/lifecycle/viewmodel/src/main/java/android/arch/lifecycle/ViewModelProvider.java b/lifecycle/viewmodel/src/main/java/android/arch/lifecycle/ViewModelProvider.java
index e01aa19..4f25ac9 100644
--- a/lifecycle/viewmodel/src/main/java/android/arch/lifecycle/ViewModelProvider.java
+++ b/lifecycle/viewmodel/src/main/java/android/arch/lifecycle/ViewModelProvider.java
@@ -93,6 +93,7 @@
      * @return A ViewModel that is an instance of the given type {@code T}.
      */
     @NonNull
+    @MainThread
     public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
         String canonicalName = modelClass.getCanonicalName();
         if (canonicalName == null) {
@@ -170,6 +171,7 @@
          * @param application an application to pass in {@link AndroidViewModel}
          * @return A valid {@link AndroidViewModelFactory}
          */
+        @NonNull
         public static AndroidViewModelFactory getInstance(@NonNull Application application) {
             if (sInstance == null) {
                 sInstance = new AndroidViewModelFactory(application);
diff --git a/lifecycle/viewmodel/src/main/java/android/arch/lifecycle/ViewModelStore.java b/lifecycle/viewmodel/src/main/java/android/arch/lifecycle/ViewModelStore.java
index a1864bb..74b5e24 100644
--- a/lifecycle/viewmodel/src/main/java/android/arch/lifecycle/ViewModelStore.java
+++ b/lifecycle/viewmodel/src/main/java/android/arch/lifecycle/ViewModelStore.java
@@ -38,11 +38,10 @@
     private final HashMap<String, ViewModel> mMap = new HashMap<>();
 
     final void put(String key, ViewModel viewModel) {
-        ViewModel oldViewModel = mMap.get(key);
+        ViewModel oldViewModel = mMap.put(key, viewModel);
         if (oldViewModel != null) {
             oldViewModel.onCleared();
         }
-        mMap.put(key, viewModel);
     }
 
     final ViewModel get(String key) {
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/api21/android/support/v4/media/session/MediaSessionCompatApi21.java b/media-compat/api21/android/support/v4/media/session/MediaSessionCompatApi21.java
index 624637a..698e37d 100644
--- a/media-compat/api21/android/support/v4/media/session/MediaSessionCompatApi21.java
+++ b/media-compat/api21/android/support/v4/media/session/MediaSessionCompatApi21.java
@@ -31,7 +31,6 @@
 import android.os.Parcelable;
 import android.os.ResultReceiver;
 import android.support.annotation.RequiresApi;
-import android.support.v4.os.BuildCompat;
 import android.util.Log;
 
 import java.lang.reflect.Field;
@@ -141,9 +140,8 @@
 
     public static boolean hasCallback(Object sessionObj) {
         Field callbackField = null;
-        String callbackFieldName = BuildCompat.isAtLeastP() ? "mCallbackHandler" : "mCallback";
         try {
-            callbackField = sessionObj.getClass().getDeclaredField(callbackFieldName);
+            callbackField = sessionObj.getClass().getDeclaredField("mCallback");
             if (callbackField != null) {
                 callbackField.setAccessible(true);
                 return callbackField.get(sessionObj) != null;
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/AndroidManifest.xml b/media-compat/src/main/AndroidManifest.xml
similarity index 100%
rename from media-compat/AndroidManifest.xml
rename to media-compat/src/main/AndroidManifest.xml
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/paging/common/src/main/java/android/arch/paging/ContiguousPagedList.java b/paging/common/src/main/java/android/arch/paging/ContiguousPagedList.java
index c622f65..2401e6e 100644
--- a/paging/common/src/main/java/android/arch/paging/ContiguousPagedList.java
+++ b/paging/common/src/main/java/android/arch/paging/ContiguousPagedList.java
@@ -53,7 +53,12 @@
             if (resultType == PageResult.INIT) {
                 mStorage.init(pageResult.leadingNulls, page, pageResult.trailingNulls,
                         pageResult.positionOffset, ContiguousPagedList.this);
-                mLastLoad = pageResult.leadingNulls + pageResult.positionOffset + page.size() / 2;
+                if (mLastLoad == LAST_LOAD_UNSPECIFIED) {
+                    // Because the ContiguousPagedList wasn't initialized with a last load position,
+                    // initialize it to the middle of the initial load
+                    mLastLoad =
+                            pageResult.leadingNulls + pageResult.positionOffset + page.size() / 2;
+                }
             } else if (resultType == PageResult.APPEND) {
                 mStorage.appendPage(page, ContiguousPagedList.this);
             } else if (resultType == PageResult.PREPEND) {
@@ -76,16 +81,20 @@
         }
     };
 
+    static final int LAST_LOAD_UNSPECIFIED = -1;
+
     ContiguousPagedList(
             @NonNull ContiguousDataSource<K, V> dataSource,
             @NonNull Executor mainThreadExecutor,
             @NonNull Executor backgroundThreadExecutor,
             @Nullable BoundaryCallback<V> boundaryCallback,
             @NonNull Config config,
-            final @Nullable K key) {
+            final @Nullable K key,
+            int lastLoad) {
         super(new PagedStorage<V>(), mainThreadExecutor, backgroundThreadExecutor,
                 boundaryCallback, config);
         mDataSource = dataSource;
+        mLastLoad = lastLoad;
 
         if (mDataSource.isInvalid()) {
             detach();
diff --git a/paging/common/src/main/java/android/arch/paging/PagedList.java b/paging/common/src/main/java/android/arch/paging/PagedList.java
index c6de5c5..6c15fb6 100644
--- a/paging/common/src/main/java/android/arch/paging/PagedList.java
+++ b/paging/common/src/main/java/android/arch/paging/PagedList.java
@@ -160,10 +160,14 @@
             @NonNull Config config,
             @Nullable K key) {
         if (dataSource.isContiguous() || !config.enablePlaceholders) {
+            int lastLoad = ContiguousPagedList.LAST_LOAD_UNSPECIFIED;
             if (!dataSource.isContiguous()) {
                 //noinspection unchecked
                 dataSource = (DataSource<K, T>) ((PositionalDataSource<T>) dataSource)
                         .wrapAsContiguousWithoutPlaceholders();
+                if (key != null) {
+                    lastLoad = (int) key;
+                }
             }
             ContiguousDataSource<K, T> contigDataSource = (ContiguousDataSource<K, T>) dataSource;
             return new ContiguousPagedList<>(contigDataSource,
@@ -171,7 +175,8 @@
                     backgroundThreadExecutor,
                     boundaryCallback,
                     config,
-                    key);
+                    key,
+                    lastLoad);
         } else {
             return new TiledPagedList<>((PositionalDataSource<T>) dataSource,
                     mainThreadExecutor,
diff --git a/paging/common/src/test/java/android/arch/paging/ContiguousPagedListTest.kt b/paging/common/src/test/java/android/arch/paging/ContiguousPagedListTest.kt
index c2c17e0..de4e3d8 100644
--- a/paging/common/src/test/java/android/arch/paging/ContiguousPagedListTest.kt
+++ b/paging/common/src/test/java/android/arch/paging/ContiguousPagedListTest.kt
@@ -138,7 +138,8 @@
             initLoadSize: Int = 40,
             prefetchDistance: Int = 20,
             listData: List<Item> = ITEMS,
-            boundaryCallback: PagedList.BoundaryCallback<Item>? = null
+            boundaryCallback: PagedList.BoundaryCallback<Item>? = null,
+            lastLoad: Int = ContiguousPagedList.LAST_LOAD_UNSPECIFIED
     ): ContiguousPagedList<Int, Item> {
         return ContiguousPagedList(
                 TestSource(listData), mMainThread, mBackgroundThread, boundaryCallback,
@@ -147,7 +148,8 @@
                         .setPageSize(pageSize)
                         .setPrefetchDistance(prefetchDistance)
                         .build(),
-                initialPosition)
+                initialPosition,
+                lastLoad)
     }
 
     @Test
@@ -309,13 +311,36 @@
     }
 
     @Test
+    fun initialLoad_lastLoad() {
+        val pagedList = createCountedPagedList(
+                initialPosition = 0,
+                initLoadSize = 20,
+                lastLoad = 4)
+        // last load is param passed
+        assertEquals(4, pagedList.mLastLoad)
+        verifyRange(0, 20, pagedList)
+    }
+
+    @Test
+    fun initialLoad_lastLoadComputed() {
+        val pagedList = createCountedPagedList(
+                initialPosition = 0,
+                initLoadSize = 20,
+                lastLoad = ContiguousPagedList.LAST_LOAD_UNSPECIFIED)
+        // last load is middle of initial load
+        assertEquals(10, pagedList.mLastLoad)
+        verifyRange(0, 20, pagedList)
+    }
+
+    @Test
     fun initialLoadAsync() {
         // Note: ignores Parameterized param
         val asyncDataSource = AsyncListDataSource(ITEMS)
         val dataSource = asyncDataSource.wrapAsContiguousWithoutPlaceholders()
         val pagedList = ContiguousPagedList(
                 dataSource, mMainThread, mBackgroundThread, null,
-                PagedList.Config.Builder().setPageSize(10).build(), null)
+                PagedList.Config.Builder().setPageSize(10).build(), null,
+                ContiguousPagedList.LAST_LOAD_UNSPECIFIED)
         val callback = mock(PagedList.Callback::class.java)
         pagedList.addWeakCallback(null, callback)
 
@@ -343,7 +368,8 @@
         val dataSource = asyncDataSource.wrapAsContiguousWithoutPlaceholders()
         val pagedList = ContiguousPagedList(
                 dataSource, mMainThread, mBackgroundThread, null,
-                PagedList.Config.Builder().setPageSize(10).build(), null)
+                PagedList.Config.Builder().setPageSize(10).build(), null,
+                ContiguousPagedList.LAST_LOAD_UNSPECIFIED)
         val callback = mock(PagedList.Callback::class.java)
 
         // capture empty snapshot
diff --git a/paging/common/src/test/java/android/arch/paging/ItemKeyedDataSourceTest.kt b/paging/common/src/test/java/android/arch/paging/ItemKeyedDataSourceTest.kt
index 4998d06..7633333 100644
--- a/paging/common/src/test/java/android/arch/paging/ItemKeyedDataSourceTest.kt
+++ b/paging/common/src/test/java/android/arch/paging/ItemKeyedDataSourceTest.kt
@@ -288,7 +288,8 @@
                 PagedList.Config.Builder()
                         .setPageSize(10)
                         .build(),
-                "")
+                "",
+                ContiguousPagedList.LAST_LOAD_UNSPECIFIED)
     }
 
     @Test
diff --git a/paging/common/src/test/java/android/arch/paging/PageKeyedDataSourceTest.kt b/paging/common/src/test/java/android/arch/paging/PageKeyedDataSourceTest.kt
index d4bbbb5..6a894a2 100644
--- a/paging/common/src/test/java/android/arch/paging/PageKeyedDataSourceTest.kt
+++ b/paging/common/src/test/java/android/arch/paging/PageKeyedDataSourceTest.kt
@@ -59,7 +59,8 @@
         // validate paging entire ItemDataSource results in full, correctly ordered data
         val pagedList = ContiguousPagedList<String, Item>(ItemDataSource(),
                 mMainThread, mBackgroundThread,
-                null, PagedList.Config.Builder().setPageSize(100).build(), null)
+                null, PagedList.Config.Builder().setPageSize(100).build(), null,
+                ContiguousPagedList.LAST_LOAD_UNSPECIFIED)
 
         // validate initial load
         assertEquals(PAGE_MAP[INIT_KEY]!!.data, pagedList)
@@ -107,7 +108,8 @@
                 PagedList.Config.Builder()
                         .setPageSize(10)
                         .build(),
-                "")
+                "",
+                ContiguousPagedList.LAST_LOAD_UNSPECIFIED)
     }
 
     @Test
diff --git a/paging/common/src/test/java/android/arch/paging/PositionalDataSourceTest.kt b/paging/common/src/test/java/android/arch/paging/PositionalDataSourceTest.kt
index 854f3a2..80b9c00 100644
--- a/paging/common/src/test/java/android/arch/paging/PositionalDataSourceTest.kt
+++ b/paging/common/src/test/java/android/arch/paging/PositionalDataSourceTest.kt
@@ -90,7 +90,8 @@
         val dataSource: PositionalDataSource<Int> = ListDataSource((0..99).toList())
         val testExecutor = TestExecutor()
         val pagedList = ContiguousPagedList(dataSource.wrapAsContiguousWithoutPlaceholders(),
-                testExecutor, testExecutor, null, config, 15)
+                testExecutor, testExecutor, null, config, 15,
+                ContiguousPagedList.LAST_LOAD_UNSPECIFIED)
 
         assertEquals((10..19).toList(), pagedList)
 
@@ -135,7 +136,8 @@
             TiledPagedList(dataSource, FailExecutor(), FailExecutor(), null, config, 0)
         } else {
             ContiguousPagedList(dataSource.wrapAsContiguousWithoutPlaceholders(),
-                    FailExecutor(), FailExecutor(), null, config, null)
+                    FailExecutor(), FailExecutor(), null, config, null,
+                    ContiguousPagedList.LAST_LOAD_UNSPECIFIED)
         }
     }
 
diff --git a/paging/integration-tests/testapp/build.gradle b/paging/integration-tests/testapp/build.gradle
index b26ca78..d1b0aec 100644
--- a/paging/integration-tests/testapp/build.gradle
+++ b/paging/integration-tests/testapp/build.gradle
@@ -30,8 +30,8 @@
     implementation(project(":lifecycle:common"))
     implementation(project(":paging:runtime"))
     implementation(MULTIDEX)
-    implementation(SUPPORT_RECYCLERVIEW, libs.support_exclude_config)
-    implementation(SUPPORT_APPCOMPAT, libs.support_exclude_config)
+    implementation(SUPPORT_RECYCLERVIEW_27, libs.support_exclude_config)
+    implementation(SUPPORT_APPCOMPAT_27, libs.support_exclude_config)
 }
 
 tasks['check'].dependsOn(tasks['connectedCheck'])
diff --git a/paging/integration-tests/testapp/src/main/java/android/arch/paging/integration/testapp/Item.java b/paging/integration-tests/testapp/src/main/java/android/arch/paging/integration/testapp/Item.java
index 70f2133..94d25a8 100644
--- a/paging/integration-tests/testapp/src/main/java/android/arch/paging/integration/testapp/Item.java
+++ b/paging/integration-tests/testapp/src/main/java/android/arch/paging/integration/testapp/Item.java
@@ -17,7 +17,7 @@
 package android.arch.paging.integration.testapp;
 
 import android.support.annotation.NonNull;
-import android.support.v7.recyclerview.extensions.DiffCallback;
+import android.support.v7.util.DiffUtil;
 
 /**
  * Sample item.
@@ -45,7 +45,7 @@
                 && this.text.equals(item.text);
     }
 
-    static final DiffCallback<Item> DIFF_CALLBACK = new DiffCallback<Item>() {
+    static final DiffUtil.ItemCallback<Item> DIFF_CALLBACK = new DiffUtil.ItemCallback<Item>() {
         @Override
         public boolean areContentsTheSame(@NonNull Item oldItem, @NonNull Item newItem) {
             return oldItem.equals(newItem);
diff --git a/paging/integration-tests/testapp/src/main/java/android/arch/paging/integration/testapp/PagedListItemAdapter.java b/paging/integration-tests/testapp/src/main/java/android/arch/paging/integration/testapp/PagedListItemAdapter.java
index d1ae5ab..9432124 100644
--- a/paging/integration-tests/testapp/src/main/java/android/arch/paging/integration/testapp/PagedListItemAdapter.java
+++ b/paging/integration-tests/testapp/src/main/java/android/arch/paging/integration/testapp/PagedListItemAdapter.java
@@ -23,7 +23,7 @@
 import android.widget.TextView;
 
 /**
- * Sample PagedList item Adapter, which uses a PagedListAdapterHelper.
+ * Sample PagedList item Adapter, which uses a AsyncPagedListDiffer.
  */
 class PagedListItemAdapter extends PagedListAdapter<Item, RecyclerView.ViewHolder> {
 
diff --git a/paging/integration-tests/testapp/src/main/java/android/arch/paging/integration/testapp/PagedListSampleActivity.java b/paging/integration-tests/testapp/src/main/java/android/arch/paging/integration/testapp/PagedListSampleActivity.java
index f1f233f..f031cdb 100644
--- a/paging/integration-tests/testapp/src/main/java/android/arch/paging/integration/testapp/PagedListSampleActivity.java
+++ b/paging/integration-tests/testapp/src/main/java/android/arch/paging/integration/testapp/PagedListSampleActivity.java
@@ -44,7 +44,7 @@
         viewModel.getLivePagedList().observe(this, new Observer<PagedList<Item>>() {
             @Override
             public void onChanged(@Nullable PagedList<Item> items) {
-                adapter.setList(items);
+                adapter.submitList(items);
             }
         });
         final Button button = findViewById(R.id.button);
diff --git a/paging/runtime/build.gradle b/paging/runtime/build.gradle
index 7e9d73c..4c42b30 100644
--- a/paging/runtime/build.gradle
+++ b/paging/runtime/build.gradle
@@ -30,7 +30,7 @@
     api(project(":lifecycle:runtime"))
     api(project(":lifecycle:livedata"))
 
-    api(SUPPORT_RECYCLERVIEW, libs.support_exclude_config)
+    api(SUPPORT_RECYCLERVIEW_27, libs.support_exclude_config)
 
     androidTestImplementation(JUNIT)
     androidTestImplementation(MOCKITO_CORE, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
@@ -48,4 +48,4 @@
     inceptionYear = "2017"
     description = "Android Paging-Runtime"
     url = SupportLibraryExtension.ARCHITECTURE_URL
-}
\ No newline at end of file
+}
diff --git a/paging/runtime/src/androidTest/java/android/arch/paging/AsyncPagedListDifferTest.kt b/paging/runtime/src/androidTest/java/android/arch/paging/AsyncPagedListDifferTest.kt
new file mode 100644
index 0000000..4817c6c
--- /dev/null
+++ b/paging/runtime/src/androidTest/java/android/arch/paging/AsyncPagedListDifferTest.kt
@@ -0,0 +1,338 @@
+/*
+ * 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.arch.paging
+
+import android.support.test.filters.SmallTest
+import android.support.v7.recyclerview.extensions.AsyncDifferConfig
+import android.support.v7.util.DiffUtil
+import android.support.v7.util.ListUpdateCallback
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertNotNull
+import org.junit.Assert.assertNull
+import org.junit.Assert.assertTrue
+import org.junit.Assert.fail
+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
+
+@SmallTest
+@RunWith(JUnit4::class)
+class AsyncPagedListDifferTest {
+    private val mMainThread = TestExecutor()
+    private val mDiffThread = TestExecutor()
+    private val mPageLoadingThread = TestExecutor()
+
+    private fun <T> createHelper(listUpdateCallback: ListUpdateCallback,
+                                 diffCallback: DiffUtil.ItemCallback<T>): AsyncPagedListDiffer<T> {
+        return AsyncPagedListDiffer(listUpdateCallback,
+                AsyncDifferConfig.Builder<T>(diffCallback)
+                        .setMainThreadExecutor(mMainThread)
+                        .setBackgroundThreadExecutor(mDiffThread)
+                        .build())
+    }
+
+    private fun <V> createPagedListFromListAndPos(
+            config: PagedList.Config, data: List<V>, initialKey: Int): PagedList<V> {
+        return PagedList.Builder<Int, V>(ListDataSource(data), config)
+                .setInitialKey(initialKey)
+                .setMainThreadExecutor(mMainThread)
+                .setBackgroundThreadExecutor(mPageLoadingThread)
+                .build()
+    }
+
+    @Test
+    fun initialState() {
+        val callback = mock(ListUpdateCallback::class.java)
+        val helper = createHelper(callback, STRING_DIFF_CALLBACK)
+        assertEquals(null, helper.currentList)
+        assertEquals(0, helper.itemCount)
+        verifyZeroInteractions(callback)
+    }
+
+    @Test
+    fun setFullList() {
+        val callback = mock(ListUpdateCallback::class.java)
+        val helper = createHelper(callback, STRING_DIFF_CALLBACK)
+        helper.submitList(StringPagedList(0, 0, "a", "b"))
+
+        assertEquals(2, helper.itemCount)
+        assertEquals("a", helper.getItem(0))
+        assertEquals("b", helper.getItem(1))
+
+        verify(callback).onInserted(0, 2)
+        verifyNoMoreInteractions(callback)
+        drain()
+        verifyNoMoreInteractions(callback)
+    }
+
+    @Test(expected = IndexOutOfBoundsException::class)
+    fun getEmpty() {
+        val helper = createHelper(IGNORE_CALLBACK, STRING_DIFF_CALLBACK)
+        helper.getItem(0)
+    }
+
+    @Test(expected = IndexOutOfBoundsException::class)
+    fun getNegative() {
+        val helper = createHelper(IGNORE_CALLBACK, STRING_DIFF_CALLBACK)
+        helper.submitList(StringPagedList(0, 0, "a", "b"))
+        helper.getItem(-1)
+    }
+
+    @Test(expected = IndexOutOfBoundsException::class)
+    fun getPastEnd() {
+        val helper = createHelper(IGNORE_CALLBACK, STRING_DIFF_CALLBACK)
+        helper.submitList(StringPagedList(0, 0, "a", "b"))
+        helper.getItem(2)
+    }
+
+    @Test
+    fun simpleStatic() {
+        val callback = mock(ListUpdateCallback::class.java)
+        val helper = createHelper(callback, STRING_DIFF_CALLBACK)
+
+        assertEquals(0, helper.itemCount)
+
+        helper.submitList(StringPagedList(2, 2, "a", "b"))
+
+        verify(callback).onInserted(0, 6)
+        verifyNoMoreInteractions(callback)
+        assertEquals(6, helper.itemCount)
+
+        assertNull(helper.getItem(0))
+        assertNull(helper.getItem(1))
+        assertEquals("a", helper.getItem(2))
+        assertEquals("b", helper.getItem(3))
+        assertNull(helper.getItem(4))
+        assertNull(helper.getItem(5))
+    }
+
+    @Test
+    fun pagingInContent() {
+        val config = PagedList.Config.Builder()
+                .setInitialLoadSizeHint(4)
+                .setPageSize(2)
+                .setPrefetchDistance(2)
+                .build()
+
+        val callback = mock(ListUpdateCallback::class.java)
+        val helper = createHelper(callback, STRING_DIFF_CALLBACK)
+
+        helper.submitList(createPagedListFromListAndPos(config, ALPHABET_LIST, 2))
+        verify(callback).onInserted(0, ALPHABET_LIST.size)
+        verifyNoMoreInteractions(callback)
+        drain()
+        verifyNoMoreInteractions(callback)
+
+        // get without triggering prefetch...
+        helper.getItem(1)
+        verifyNoMoreInteractions(callback)
+        drain()
+        verifyNoMoreInteractions(callback)
+
+        // get triggering prefetch...
+        helper.getItem(2)
+        verifyNoMoreInteractions(callback)
+        drain()
+        verify(callback).onChanged(4, 2, null)
+        verifyNoMoreInteractions(callback)
+
+        // get with no data loaded nearby...
+        helper.getItem(12)
+        verifyNoMoreInteractions(callback)
+        drain()
+        verify(callback).onChanged(10, 2, null)
+        verify(callback).onChanged(12, 2, null)
+        verify(callback).onChanged(14, 2, null)
+        verifyNoMoreInteractions(callback)
+
+        // finally, clear
+        helper.submitList(null)
+        verify(callback).onRemoved(0, 26)
+        drain()
+        verifyNoMoreInteractions(callback)
+    }
+
+    @Test
+    fun simpleSwap() {
+        // Page size large enough to load
+        val config = PagedList.Config.Builder()
+                .setPageSize(50)
+                .build()
+
+        val callback = mock(ListUpdateCallback::class.java)
+        val helper = createHelper(callback, STRING_DIFF_CALLBACK)
+
+        // initial list missing one item (immediate)
+        helper.submitList(createPagedListFromListAndPos(config, ALPHABET_LIST.subList(0, 25), 0))
+        verify(callback).onInserted(0, 25)
+        verifyNoMoreInteractions(callback)
+        assertEquals(helper.itemCount, 25)
+        drain()
+        verifyNoMoreInteractions(callback)
+
+        // pass second list with full data
+        helper.submitList(createPagedListFromListAndPos(config, ALPHABET_LIST, 0))
+        verifyNoMoreInteractions(callback)
+        drain()
+        verify(callback).onInserted(25, 1)
+        verifyNoMoreInteractions(callback)
+        assertEquals(helper.itemCount, 26)
+
+        // finally, clear (immediate)
+        helper.submitList(null)
+        verify(callback).onRemoved(0, 26)
+        verifyNoMoreInteractions(callback)
+        drain()
+        verifyNoMoreInteractions(callback)
+    }
+
+    @Test
+    fun newPageWhileDiffing() {
+        val config = PagedList.Config.Builder()
+                .setInitialLoadSizeHint(4)
+                .setPageSize(2)
+                .setPrefetchDistance(2)
+                .build()
+
+        val callback = mock(ListUpdateCallback::class.java)
+        val helper = createHelper(callback, STRING_DIFF_CALLBACK)
+
+        helper.submitList(createPagedListFromListAndPos(config, ALPHABET_LIST, 2))
+        verify(callback).onInserted(0, ALPHABET_LIST.size)
+        verifyNoMoreInteractions(callback)
+        drain()
+        verifyNoMoreInteractions(callback)
+        assertNotNull(helper.currentList)
+        assertFalse(helper.currentList!!.isImmutable)
+
+        // trigger page loading
+        helper.getItem(10)
+        helper.submitList(createPagedListFromListAndPos(config, ALPHABET_LIST, 2))
+        verifyNoMoreInteractions(callback)
+
+        // drain page fetching, but list became immutable, page will be ignored
+        drainExceptDiffThread()
+        verifyNoMoreInteractions(callback)
+        assertNotNull(helper.currentList)
+        assertTrue(helper.currentList!!.isImmutable)
+
+        // finally full drain, which signals nothing, since 1st pagedlist == 2nd pagedlist
+        drain()
+        verifyNoMoreInteractions(callback)
+        assertNotNull(helper.currentList)
+        assertFalse(helper.currentList!!.isImmutable)
+    }
+
+    @Test
+    fun itemCountUpdatedBeforeListUpdateCallbacks() {
+        // verify that itemCount is updated in the helper before dispatching ListUpdateCallbacks
+
+        val expectedCount = intArrayOf(0)
+        // provides access to helper, which must be constructed after callback
+        val helperAccessor = arrayOf<AsyncPagedListDiffer<*>?>(null)
+
+        val callback = object : ListUpdateCallback {
+            override fun onInserted(position: Int, count: Int) {
+                assertEquals(expectedCount[0], helperAccessor[0]!!.itemCount)
+            }
+
+            override fun onRemoved(position: Int, count: Int) {
+                assertEquals(expectedCount[0], helperAccessor[0]!!.itemCount)
+            }
+
+            override fun onMoved(fromPosition: Int, toPosition: Int) {
+                fail("not expected")
+            }
+
+            override fun onChanged(position: Int, count: Int, payload: Any) {
+                fail("not expected")
+            }
+        }
+
+        val helper = createHelper(callback, STRING_DIFF_CALLBACK)
+        helperAccessor[0] = helper
+
+        val config = PagedList.Config.Builder()
+                .setPageSize(20)
+                .build()
+
+        // in the fast-add case...
+        expectedCount[0] = 5
+        assertEquals(0, helper.itemCount)
+        helper.submitList(createPagedListFromListAndPos(config, ALPHABET_LIST.subList(0, 5), 0))
+        assertEquals(5, helper.itemCount)
+
+        // in the slow, diff on BG thread case...
+        expectedCount[0] = 10
+        assertEquals(5, helper.itemCount)
+        helper.submitList(createPagedListFromListAndPos(config, ALPHABET_LIST.subList(0, 10), 0))
+        drain()
+        assertEquals(10, helper.itemCount)
+
+        // and in the fast-remove case
+        expectedCount[0] = 0
+        assertEquals(10, helper.itemCount)
+        helper.submitList(null)
+        assertEquals(0, helper.itemCount)
+    }
+
+    private fun drainExceptDiffThread() {
+        var executed: Boolean
+        do {
+            executed = mPageLoadingThread.executeAll()
+            executed = mMainThread.executeAll() or executed
+        } while (executed)
+    }
+
+    private fun drain() {
+        var executed: Boolean
+        do {
+            executed = mPageLoadingThread.executeAll()
+            executed = mDiffThread.executeAll() or executed
+            executed = mMainThread.executeAll() or executed
+        } while (executed)
+    }
+
+    companion object {
+        private val ALPHABET_LIST = List(26) { "" + 'a' + it }
+
+        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/paging/runtime/src/androidTest/java/android/arch/paging/PagedListAdapterHelperTest.kt b/paging/runtime/src/androidTest/java/android/arch/paging/PagedListAdapterHelperTest.kt
deleted file mode 100644
index d50b8d9..0000000
--- a/paging/runtime/src/androidTest/java/android/arch/paging/PagedListAdapterHelperTest.kt
+++ /dev/null
@@ -1,339 +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.arch.paging
-
-import android.support.test.filters.SmallTest
-import android.support.v7.recyclerview.extensions.DiffCallback
-import android.support.v7.recyclerview.extensions.ListAdapterConfig
-import android.support.v7.util.ListUpdateCallback
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertFalse
-import org.junit.Assert.assertNotNull
-import org.junit.Assert.assertNull
-import org.junit.Assert.assertTrue
-import org.junit.Assert.fail
-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
-
-@SmallTest
-@RunWith(JUnit4::class)
-class PagedListAdapterHelperTest {
-    private val mMainThread = TestExecutor()
-    private val mDiffThread = TestExecutor()
-    private val mPageLoadingThread = TestExecutor()
-
-    private fun <T> createHelper(listUpdateCallback: ListUpdateCallback,
-                                 diffCallback: DiffCallback<T>): PagedListAdapterHelper<T> {
-        return PagedListAdapterHelper(listUpdateCallback,
-                ListAdapterConfig.Builder<T>()
-                        .setDiffCallback(diffCallback)
-                        .setMainThreadExecutor(mMainThread)
-                        .setBackgroundThreadExecutor(mDiffThread)
-                        .build())
-    }
-
-    private fun <V> createPagedListFromListAndPos(
-            config: PagedList.Config, data: List<V>, initialKey: Int): PagedList<V> {
-        return PagedList.Builder<Int, V>(ListDataSource(data), config)
-                .setInitialKey(initialKey)
-                .setMainThreadExecutor(mMainThread)
-                .setBackgroundThreadExecutor(mPageLoadingThread)
-                .build()
-    }
-
-    @Test
-    fun initialState() {
-        val callback = mock(ListUpdateCallback::class.java)
-        val helper = createHelper(callback, STRING_DIFF_CALLBACK)
-        assertEquals(null, helper.currentList)
-        assertEquals(0, helper.itemCount)
-        verifyZeroInteractions(callback)
-    }
-
-    @Test
-    fun setFullList() {
-        val callback = mock(ListUpdateCallback::class.java)
-        val helper = createHelper(callback, STRING_DIFF_CALLBACK)
-        helper.setList(StringPagedList(0, 0, "a", "b"))
-
-        assertEquals(2, helper.itemCount)
-        assertEquals("a", helper.getItem(0))
-        assertEquals("b", helper.getItem(1))
-
-        verify(callback).onInserted(0, 2)
-        verifyNoMoreInteractions(callback)
-        drain()
-        verifyNoMoreInteractions(callback)
-    }
-
-    @Test(expected = IndexOutOfBoundsException::class)
-    fun getEmpty() {
-        val helper = createHelper(IGNORE_CALLBACK, STRING_DIFF_CALLBACK)
-        helper.getItem(0)
-    }
-
-    @Test(expected = IndexOutOfBoundsException::class)
-    fun getNegative() {
-        val helper = createHelper(IGNORE_CALLBACK, STRING_DIFF_CALLBACK)
-        helper.setList(StringPagedList(0, 0, "a", "b"))
-        helper.getItem(-1)
-    }
-
-    @Test(expected = IndexOutOfBoundsException::class)
-    fun getPastEnd() {
-        val helper = createHelper(IGNORE_CALLBACK, STRING_DIFF_CALLBACK)
-        helper.setList(StringPagedList(0, 0, "a", "b"))
-        helper.getItem(2)
-    }
-
-    @Test
-    fun simpleStatic() {
-        val callback = mock(ListUpdateCallback::class.java)
-        val helper = createHelper(callback, STRING_DIFF_CALLBACK)
-
-        assertEquals(0, helper.itemCount)
-
-        helper.setList(StringPagedList(2, 2, "a", "b"))
-
-        verify(callback).onInserted(0, 6)
-        verifyNoMoreInteractions(callback)
-        assertEquals(6, helper.itemCount)
-
-        assertNull(helper.getItem(0))
-        assertNull(helper.getItem(1))
-        assertEquals("a", helper.getItem(2))
-        assertEquals("b", helper.getItem(3))
-        assertNull(helper.getItem(4))
-        assertNull(helper.getItem(5))
-    }
-
-    @Test
-    fun pagingInContent() {
-        val config = PagedList.Config.Builder()
-                .setInitialLoadSizeHint(4)
-                .setPageSize(2)
-                .setPrefetchDistance(2)
-                .build()
-
-        val callback = mock(ListUpdateCallback::class.java)
-        val helper = createHelper(callback, STRING_DIFF_CALLBACK)
-
-        helper.setList(createPagedListFromListAndPos(config, ALPHABET_LIST, 2))
-        verify(callback).onInserted(0, ALPHABET_LIST.size)
-        verifyNoMoreInteractions(callback)
-        drain()
-        verifyNoMoreInteractions(callback)
-
-        // get without triggering prefetch...
-        helper.getItem(1)
-        verifyNoMoreInteractions(callback)
-        drain()
-        verifyNoMoreInteractions(callback)
-
-        // get triggering prefetch...
-        helper.getItem(2)
-        verifyNoMoreInteractions(callback)
-        drain()
-        verify(callback).onChanged(4, 2, null)
-        verifyNoMoreInteractions(callback)
-
-        // get with no data loaded nearby...
-        helper.getItem(12)
-        verifyNoMoreInteractions(callback)
-        drain()
-        verify(callback).onChanged(10, 2, null)
-        verify(callback).onChanged(12, 2, null)
-        verify(callback).onChanged(14, 2, null)
-        verifyNoMoreInteractions(callback)
-
-        // finally, clear
-        helper.setList(null)
-        verify(callback).onRemoved(0, 26)
-        drain()
-        verifyNoMoreInteractions(callback)
-    }
-
-    @Test
-    fun simpleSwap() {
-        // Page size large enough to load
-        val config = PagedList.Config.Builder()
-                .setPageSize(50)
-                .build()
-
-        val callback = mock(ListUpdateCallback::class.java)
-        val helper = createHelper(callback, STRING_DIFF_CALLBACK)
-
-        // initial list missing one item (immediate)
-        helper.setList(createPagedListFromListAndPos(config, ALPHABET_LIST.subList(0, 25), 0))
-        verify(callback).onInserted(0, 25)
-        verifyNoMoreInteractions(callback)
-        assertEquals(helper.itemCount, 25)
-        drain()
-        verifyNoMoreInteractions(callback)
-
-        // pass second list with full data
-        helper.setList(createPagedListFromListAndPos(config, ALPHABET_LIST, 0))
-        verifyNoMoreInteractions(callback)
-        drain()
-        verify(callback).onInserted(25, 1)
-        verifyNoMoreInteractions(callback)
-        assertEquals(helper.itemCount, 26)
-
-        // finally, clear (immediate)
-        helper.setList(null)
-        verify(callback).onRemoved(0, 26)
-        verifyNoMoreInteractions(callback)
-        drain()
-        verifyNoMoreInteractions(callback)
-    }
-
-    @Test
-    fun newPageWhileDiffing() {
-        val config = PagedList.Config.Builder()
-                .setInitialLoadSizeHint(4)
-                .setPageSize(2)
-                .setPrefetchDistance(2)
-                .build()
-
-        val callback = mock(ListUpdateCallback::class.java)
-        val helper = createHelper(callback, STRING_DIFF_CALLBACK)
-
-        helper.setList(createPagedListFromListAndPos(config, ALPHABET_LIST, 2))
-        verify(callback).onInserted(0, ALPHABET_LIST.size)
-        verifyNoMoreInteractions(callback)
-        drain()
-        verifyNoMoreInteractions(callback)
-        assertNotNull(helper.currentList)
-        assertFalse(helper.currentList!!.isImmutable)
-
-        // trigger page loading
-        helper.getItem(10)
-        helper.setList(createPagedListFromListAndPos(config, ALPHABET_LIST, 2))
-        verifyNoMoreInteractions(callback)
-
-        // drain page fetching, but list became immutable, page will be ignored
-        drainExceptDiffThread()
-        verifyNoMoreInteractions(callback)
-        assertNotNull(helper.currentList)
-        assertTrue(helper.currentList!!.isImmutable)
-
-        // finally full drain, which signals nothing, since 1st pagedlist == 2nd pagedlist
-        drain()
-        verifyNoMoreInteractions(callback)
-        assertNotNull(helper.currentList)
-        assertFalse(helper.currentList!!.isImmutable)
-    }
-
-    @Test
-    fun itemCountUpdatedBeforeListUpdateCallbacks() {
-        // verify that itemCount is updated in the helper before dispatching ListUpdateCallbacks
-
-        val expectedCount = intArrayOf(0)
-        // provides access to helper, which must be constructed after callback
-        val helperAccessor = arrayOf<PagedListAdapterHelper<*>?>(null)
-
-        val callback = object : ListUpdateCallback {
-            override fun onInserted(position: Int, count: Int) {
-                assertEquals(expectedCount[0], helperAccessor[0]!!.itemCount)
-            }
-
-            override fun onRemoved(position: Int, count: Int) {
-                assertEquals(expectedCount[0], helperAccessor[0]!!.itemCount)
-            }
-
-            override fun onMoved(fromPosition: Int, toPosition: Int) {
-                fail("not expected")
-            }
-
-            override fun onChanged(position: Int, count: Int, payload: Any) {
-                fail("not expected")
-            }
-        }
-
-        val helper = createHelper(callback, STRING_DIFF_CALLBACK)
-        helperAccessor[0] = helper
-
-        val config = PagedList.Config.Builder()
-                .setPageSize(20)
-                .build()
-
-        // in the fast-add case...
-        expectedCount[0] = 5
-        assertEquals(0, helper.itemCount)
-        helper.setList(createPagedListFromListAndPos(config, ALPHABET_LIST.subList(0, 5), 0))
-        assertEquals(5, helper.itemCount)
-
-        // in the slow, diff on BG thread case...
-        expectedCount[0] = 10
-        assertEquals(5, helper.itemCount)
-        helper.setList(createPagedListFromListAndPos(config, ALPHABET_LIST.subList(0, 10), 0))
-        drain()
-        assertEquals(10, helper.itemCount)
-
-        // and in the fast-remove case
-        expectedCount[0] = 0
-        assertEquals(10, helper.itemCount)
-        helper.setList(null)
-        assertEquals(0, helper.itemCount)
-    }
-
-    private fun drainExceptDiffThread() {
-        var executed: Boolean
-        do {
-            executed = mPageLoadingThread.executeAll()
-            executed = mMainThread.executeAll() or executed
-        } while (executed)
-    }
-
-    private fun drain() {
-        var executed: Boolean
-        do {
-            executed = mPageLoadingThread.executeAll()
-            executed = mDiffThread.executeAll() or executed
-            executed = mMainThread.executeAll() or executed
-        } while (executed)
-    }
-
-    companion object {
-        private val ALPHABET_LIST = List(26) { "" + 'a' + it }
-
-        private val STRING_DIFF_CALLBACK = object : DiffCallback<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/paging/runtime/src/androidTest/java/android/arch/paging/PagedStorageDiffHelperTest.kt b/paging/runtime/src/androidTest/java/android/arch/paging/PagedStorageDiffHelperTest.kt
index 44a98e9..8b885f2 100644
--- a/paging/runtime/src/androidTest/java/android/arch/paging/PagedStorageDiffHelperTest.kt
+++ b/paging/runtime/src/androidTest/java/android/arch/paging/PagedStorageDiffHelperTest.kt
@@ -17,7 +17,7 @@
 package android.arch.paging
 
 import android.support.test.filters.SmallTest
-import android.support.v7.recyclerview.extensions.DiffCallback
+import android.support.v7.util.DiffUtil
 import android.support.v7.util.ListUpdateCallback
 import org.junit.Assert.assertEquals
 import org.junit.Test
@@ -97,7 +97,7 @@
     }
 
     companion object {
-        private val DIFF_CALLBACK = object : DiffCallback<String>() {
+        private val DIFF_CALLBACK = object : DiffUtil.ItemCallback<String>() {
             override fun areItemsTheSame(oldItem: String, newItem: String): Boolean {
                 // first char means same item
                 return oldItem[0] == newItem[0]
@@ -111,8 +111,7 @@
         private fun validateTwoListDiff(oldList: PagedStorage<String>,
                                         newList: PagedStorage<String>,
                                         validator: (callback: ListUpdateCallback) -> Unit) {
-            val diffResult = PagedStorageDiffHelper.computeDiff(
-                    oldList, newList, DIFF_CALLBACK)
+            val diffResult = PagedStorageDiffHelper.computeDiff(oldList, newList, DIFF_CALLBACK)
 
             val listUpdateCallback = mock(ListUpdateCallback::class.java)
             PagedStorageDiffHelper.dispatchDiff(listUpdateCallback, oldList, newList, diffResult)
diff --git a/paging/runtime/src/main/java/android/arch/paging/AsyncPagedListDiffer.java b/paging/runtime/src/main/java/android/arch/paging/AsyncPagedListDiffer.java
new file mode 100644
index 0000000..5ef00ec
--- /dev/null
+++ b/paging/runtime/src/main/java/android/arch/paging/AsyncPagedListDiffer.java
@@ -0,0 +1,348 @@
+/*
+ * 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.arch.paging;
+
+import android.arch.lifecycle.LiveData;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v7.recyclerview.extensions.AsyncDifferConfig;
+import android.support.v7.util.AdapterListUpdateCallback;
+import android.support.v7.util.DiffUtil;
+import android.support.v7.util.ListUpdateCallback;
+import android.support.v7.widget.RecyclerView;
+
+/**
+ * Helper object for mapping a {@link PagedList} into a
+ * {@link android.support.v7.widget.RecyclerView.Adapter RecyclerView.Adapter}.
+ * <p>
+ * For simplicity, the {@link PagedListAdapter} wrapper class can often be used instead of the
+ * differ directly. This diff class is exposed for complex cases, and where overriding an adapter
+ * base class to support paging isn't convenient.
+ * <p>
+ * When consuming a {@link LiveData} of PagedList, you can observe updates and dispatch them
+ * directly to {@link #submitList(PagedList)}. The AsyncPagedListDiffer then can present this
+ * updating data set simply for an adapter. It listens to PagedList loading callbacks, and uses
+ * DiffUtil on a background thread to compute updates as new PagedLists are received.
+ * <p>
+ * It provides a simple list-like API with {@link #getItem(int)} and {@link #getItemCount()} for an
+ * adapter to acquire and present data objects.
+ * <p>
+ * A complete usage pattern with Room would look like this:
+ * <pre>
+ * {@literal @}Dao
+ * interface UserDao {
+ *     {@literal @}Query("SELECT * FROM user ORDER BY lastName ASC")
+ *     public abstract DataSource.Factory&lt;Integer, User> usersByLastName();
+ * }
+ *
+ * class MyViewModel extends ViewModel {
+ *     public final LiveData&lt;PagedList&lt;User>> usersList;
+ *     public MyViewModel(UserDao userDao) {
+ *         usersList = new LivePagedListBuilder&lt;>(
+ *                 userDao.usersByLastName(), /* page size {@literal *}/ 20).build();
+ *     }
+ * }
+ *
+ * class MyActivity extends AppCompatActivity {
+ *     {@literal @}Override
+ *     public void onCreate(Bundle savedState) {
+ *         super.onCreate(savedState);
+ *         MyViewModel viewModel = ViewModelProviders.of(this).get(MyViewModel.class);
+ *         RecyclerView recyclerView = findViewById(R.id.user_list);
+ *         final UserAdapter&lt;User> adapter = new UserAdapter();
+ *         viewModel.usersList.observe(this, pagedList -> adapter.submitList(pagedList));
+ *         recyclerView.setAdapter(adapter);
+ *     }
+ * }
+ *
+ * class UserAdapter extends RecyclerView.Adapter&lt;UserViewHolder> {
+ *     private final AsyncPagedListDiffer&lt;User> mDiffer
+ *             = new AsyncPagedListDiffer(this, DIFF_CALLBACK);
+ *     {@literal @}Override
+ *     public int getItemCount() {
+ *         return mDiffer.getItemCount();
+ *     }
+ *     public void submitList(PagedList&lt;User> pagedList) {
+ *         mDiffer.submitList(pagedList);
+ *     }
+ *     {@literal @}Override
+ *     public void onBindViewHolder(UserViewHolder holder, int position) {
+ *         User user = mDiffer.getItem(position);
+ *         if (user != null) {
+ *             holder.bindTo(user);
+ *         } else {
+ *             // Null defines a placeholder item - AsyncPagedListDiffer will automatically
+ *             // invalidate this row when the actual object is loaded from the database
+ *             holder.clear();
+ *         }
+ *     }
+ *     public static final DiffUtil.ItemCallback&lt;User> DIFF_CALLBACK =
+ *             new DiffUtil.ItemCallback&lt;User>() {
+ *          {@literal @}Override
+ *          public boolean areItemsTheSame(
+ *                  {@literal @}NonNull User oldUser, {@literal @}NonNull User newUser) {
+ *              // User properties may have changed if reloaded from the DB, but ID is fixed
+ *              return oldUser.getId() == newUser.getId();
+ *          }
+ *          {@literal @}Override
+ *          public boolean areContentsTheSame(
+ *                  {@literal @}NonNull User oldUser, {@literal @}NonNull User newUser) {
+ *              // NOTE: if you use equals, your object must properly override Object#equals()
+ *              // Incorrectly returning false here will result in too many animations.
+ *              return oldUser.equals(newUser);
+ *          }
+ *      }
+ * }</pre>
+ *
+ * @param <T> Type of the PagedLists this differ will receive.
+ */
+public class AsyncPagedListDiffer<T> {
+    // updateCallback notifications must only be notified *after* new data and item count are stored
+    // this ensures Adapter#notifyItemRangeInserted etc are accessing the new data
+    private final ListUpdateCallback mUpdateCallback;
+    private final AsyncDifferConfig<T> mConfig;
+
+    // TODO: REAL API
+    interface PagedListListener<T> {
+        void onCurrentListChanged(@Nullable PagedList<T> currentList);
+    }
+
+    @Nullable
+    PagedListListener<T> mListener;
+
+    private boolean mIsContiguous;
+
+    private PagedList<T> mPagedList;
+    private PagedList<T> mSnapshot;
+
+    // Max generation of currently scheduled runnable
+    private int mMaxScheduledGeneration;
+
+    /**
+     * Convenience for {@code AsyncPagedListDiffer(new AdapterListUpdateCallback(adapter),
+     * new AsyncDifferConfig.Builder<T>(diffCallback).build();}
+     *
+     * @param adapter Adapter that will receive update signals.
+     * @param diffCallback The {@link DiffUtil.ItemCallback DiffUtil.ItemCallback} instance to
+     * compare items in the list.
+     */
+    @SuppressWarnings("WeakerAccess")
+    public AsyncPagedListDiffer(@NonNull RecyclerView.Adapter adapter,
+            @NonNull DiffUtil.ItemCallback<T> diffCallback) {
+        mUpdateCallback = new AdapterListUpdateCallback(adapter);
+        mConfig = new AsyncDifferConfig.Builder<T>(diffCallback).build();
+    }
+
+    @SuppressWarnings("WeakerAccess")
+    public AsyncPagedListDiffer(@NonNull ListUpdateCallback listUpdateCallback,
+            @NonNull AsyncDifferConfig<T> config) {
+        mUpdateCallback = listUpdateCallback;
+        mConfig = config;
+    }
+
+    private PagedList.Callback mPagedListCallback = new PagedList.Callback() {
+        @Override
+        public void onInserted(int position, int count) {
+            mUpdateCallback.onInserted(position, count);
+        }
+
+        @Override
+        public void onRemoved(int position, int count) {
+            mUpdateCallback.onRemoved(position, count);
+        }
+
+        @Override
+        public void onChanged(int position, int count) {
+            // NOTE: pass a null payload to convey null -> item
+            mUpdateCallback.onChanged(position, count, null);
+        }
+    };
+
+    /**
+     * Get the item from the current PagedList at the specified index.
+     * <p>
+     * Note that this operates on both loaded items and null padding within the PagedList.
+     *
+     * @param index Index of item to get, must be >= 0, and &lt; {@link #getItemCount()}.
+     * @return The item, or null, if a null placeholder is at the specified position.
+     */
+    @SuppressWarnings("WeakerAccess")
+    @Nullable
+    public T getItem(int index) {
+        if (mPagedList == null) {
+            if (mSnapshot == null) {
+                throw new IndexOutOfBoundsException(
+                        "Item count is zero, getItem() call is invalid");
+            } else {
+                return mSnapshot.get(index);
+            }
+        }
+
+        mPagedList.loadAround(index);
+        return mPagedList.get(index);
+    }
+
+    /**
+     * Get the number of items currently presented by this Differ. This value can be directly
+     * returned to {@link RecyclerView.Adapter#getItemCount()}.
+     *
+     * @return Number of items being presented.
+     */
+    @SuppressWarnings("WeakerAccess")
+    public int getItemCount() {
+        if (mPagedList != null) {
+            return mPagedList.size();
+        }
+
+        return mSnapshot == null ? 0 : mSnapshot.size();
+    }
+
+    /**
+     * Pass a new PagedList to the differ.
+     * <p>
+     * If a PagedList is already present, a diff will be computed asynchronously on a background
+     * thread. When the diff is computed, it will be applied (dispatched to the
+     * {@link ListUpdateCallback}), and the new PagedList will be swapped in as the
+     * {@link #getCurrentList() current list}.
+     *
+     * @param pagedList The new PagedList.
+     */
+    public void submitList(final PagedList<T> pagedList) {
+        if (pagedList != null) {
+            if (mPagedList == null && mSnapshot == null) {
+                mIsContiguous = pagedList.isContiguous();
+            } else {
+                if (pagedList.isContiguous() != mIsContiguous) {
+                    throw new IllegalArgumentException("AsyncPagedListDiffer cannot handle both"
+                            + " contiguous and non-contiguous lists.");
+                }
+            }
+        }
+
+        if (pagedList == mPagedList) {
+            // nothing to do
+            return;
+        }
+
+        // incrementing generation means any currently-running diffs are discarded when they finish
+        final int runGeneration = ++mMaxScheduledGeneration;
+
+        if (pagedList == null) {
+            int removedCount = getItemCount();
+            if (mPagedList != null) {
+                mPagedList.removeWeakCallback(mPagedListCallback);
+                mPagedList = null;
+            } else if (mSnapshot != null) {
+                mSnapshot = null;
+            }
+            // dispatch update callback after updating mPagedList/mSnapshot
+            mUpdateCallback.onRemoved(0, removedCount);
+            if (mListener != null) {
+                mListener.onCurrentListChanged(null);
+            }
+            return;
+        }
+
+        if (mPagedList == null && mSnapshot == null) {
+            // fast simple first insert
+            mPagedList = pagedList;
+            pagedList.addWeakCallback(null, mPagedListCallback);
+
+            // dispatch update callback after updating mPagedList/mSnapshot
+            mUpdateCallback.onInserted(0, pagedList.size());
+
+            if (mListener != null) {
+                mListener.onCurrentListChanged(pagedList);
+            }
+            return;
+        }
+
+        if (mPagedList != null) {
+            // first update scheduled on this list, so capture mPages as a snapshot, removing
+            // callbacks so we don't have resolve updates against a moving target
+            mPagedList.removeWeakCallback(mPagedListCallback);
+            mSnapshot = (PagedList<T>) mPagedList.snapshot();
+            mPagedList = null;
+        }
+
+        if (mSnapshot == null || mPagedList != null) {
+            throw new IllegalStateException("must be in snapshot state to diff");
+        }
+
+        final PagedList<T> oldSnapshot = mSnapshot;
+        final PagedList<T> newSnapshot = (PagedList<T>) pagedList.snapshot();
+        mConfig.getBackgroundThreadExecutor().execute(new Runnable() {
+            @Override
+            @SuppressWarnings("RestrictedApi")
+            public void run() {
+                final DiffUtil.DiffResult result;
+                result = PagedStorageDiffHelper.computeDiff(
+                        oldSnapshot.mStorage,
+                        newSnapshot.mStorage,
+                        mConfig.getDiffCallback());
+
+                mConfig.getMainThreadExecutor().execute(new Runnable() {
+                    @Override
+                    public void run() {
+                        if (mMaxScheduledGeneration == runGeneration) {
+                            latchPagedList(pagedList, newSnapshot, result);
+                        }
+                    }
+                });
+            }
+        });
+    }
+
+    private void latchPagedList(
+            PagedList<T> newList, PagedList<T> diffSnapshot,
+            DiffUtil.DiffResult diffResult) {
+        if (mSnapshot == null || mPagedList != null) {
+            throw new IllegalStateException("must be in snapshot state to apply diff");
+        }
+
+        PagedList<T> previousSnapshot = mSnapshot;
+        mPagedList = newList;
+        mSnapshot = null;
+
+        // dispatch update callback after updating mPagedList/mSnapshot
+        PagedStorageDiffHelper.dispatchDiff(mUpdateCallback,
+                previousSnapshot.mStorage, newList.mStorage, diffResult);
+
+        newList.addWeakCallback(diffSnapshot, mPagedListCallback);
+        if (mListener != null) {
+            mListener.onCurrentListChanged(mPagedList);
+        }
+    }
+
+    /**
+     * Returns the PagedList currently being displayed by the differ.
+     * <p>
+     * This is not necessarily the most recent list passed to {@link #submitList(PagedList)},
+     * because a diff is computed asynchronously between the new list and the current list before
+     * updating the currentList value. May be null if no PagedList is being presented.
+     *
+     * @return The list currently being displayed, may be null.
+     */
+    @SuppressWarnings("WeakerAccess")
+    @Nullable
+    public PagedList<T> getCurrentList() {
+        if (mSnapshot != null) {
+            return mSnapshot;
+        }
+        return mPagedList;
+    }
+}
diff --git a/paging/runtime/src/main/java/android/arch/paging/PagedListAdapter.java b/paging/runtime/src/main/java/android/arch/paging/PagedListAdapter.java
index be23271..4728828 100644
--- a/paging/runtime/src/main/java/android/arch/paging/PagedListAdapter.java
+++ b/paging/runtime/src/main/java/android/arch/paging/PagedListAdapter.java
@@ -18,20 +18,20 @@
 
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
-import android.support.v7.recyclerview.extensions.DiffCallback;
-import android.support.v7.recyclerview.extensions.ListAdapterConfig;
-import android.support.v7.recyclerview.extensions.ListAdapterHelper;
+import android.support.v7.recyclerview.extensions.AsyncDifferConfig;
+import android.support.v7.util.AdapterListUpdateCallback;
+import android.support.v7.util.DiffUtil;
 import android.support.v7.widget.RecyclerView;
 
 /**
  * {@link RecyclerView.Adapter RecyclerView.Adapter} base class for presenting paged data from
  * {@link PagedList}s in a {@link RecyclerView}.
  * <p>
- * This class is a convenience wrapper around PagedListAdapterHelper that implements common default
- * behavior for item counting, and listening to PagedList update callbacks.
+ * This class is a convenience wrapper around {@link AsyncPagedListDiffer} that implements common
+ * default behavior for item counting, and listening to PagedList update callbacks.
  * <p>
  * While using a LiveData&lt;PagedList> is an easy way to provide data to the adapter, it isn't
- * required - you can use {@link #setList(PagedList)} when new lists are available.
+ * required - you can use {@link #submitList(PagedList)} when new lists are available.
  * <p>
  * PagedListAdapter listens to PagedList loading callbacks as pages are loaded, and uses DiffUtil on
  * a background thread to compute fine grained updates as new PagedLists are received.
@@ -62,7 +62,7 @@
  *         MyViewModel viewModel = ViewModelProviders.of(this).get(MyViewModel.class);
  *         RecyclerView recyclerView = findViewById(R.id.user_list);
  *         UserAdapter&lt;User> adapter = new UserAdapter();
- *         viewModel.usersList.observe(this, pagedList -> adapter.setList(pagedList));
+ *         viewModel.usersList.observe(this, pagedList -> adapter.submitList(pagedList));
  *         recyclerView.setAdapter(adapter);
  *     }
  * }
@@ -82,7 +82,8 @@
  *             holder.clear();
  *         }
  *     }
- *     public static final DiffCallback&lt;User> DIFF_CALLBACK = new DiffCallback&lt;User>() {
+ *     public static final DiffUtil.ItemCallback&lt;User> DIFF_CALLBACK =
+ *             new DiffUtil.ItemCallback&lt;User>() {
  *         {@literal @}Override
  *         public boolean areItemsTheSame(
  *                 {@literal @}NonNull User oldUser, {@literal @}NonNull User newUser) {
@@ -100,17 +101,17 @@
  * }</pre>
  *
  * Advanced users that wish for more control over adapter behavior, or to provide a specific base
- * class should refer to {@link PagedListAdapterHelper}, which provides the mapping from paging
+ * class should refer to {@link AsyncPagedListDiffer}, which provides the mapping from paging
  * events to adapter-friendly callbacks.
  *
- * @param <T> Type of the PagedLists this helper will receive.
+ * @param <T> Type of the PagedLists this Adapter will receive.
  * @param <VH> A class that extends ViewHolder that will be used by the adapter.
  */
 public abstract class PagedListAdapter<T, VH extends RecyclerView.ViewHolder>
         extends RecyclerView.Adapter<VH> {
-    private final PagedListAdapterHelper<T> mHelper;
-    private final PagedListAdapterHelper.PagedListListener<T> mListener =
-            new PagedListAdapterHelper.PagedListListener<T>() {
+    private final AsyncPagedListDiffer<T> mDiffer;
+    private final AsyncPagedListDiffer.PagedListListener<T> mListener =
+            new AsyncPagedListDiffer.PagedListListener<T>() {
         @Override
         public void onCurrentListChanged(@Nullable PagedList<T> currentList) {
             PagedListAdapter.this.onCurrentListChanged(currentList);
@@ -121,20 +122,21 @@
      * Creates a PagedListAdapter with default threading and
      * {@link android.support.v7.util.ListUpdateCallback}.
      *
-     * Convenience for {@link #PagedListAdapter(ListAdapterConfig)}, which uses default threading
+     * Convenience for {@link #PagedListAdapter(AsyncDifferConfig)}, which uses default threading
      * behavior.
      *
-     * @param diffCallback The {@link DiffCallback} instance to compare items in the list.
+     * @param diffCallback The {@link DiffUtil.ItemCallback DiffUtil.ItemCallback} instance to
+     *                     compare items in the list.
      */
-    protected PagedListAdapter(@NonNull DiffCallback<T> diffCallback) {
-        mHelper = new PagedListAdapterHelper<>(this, diffCallback);
-        mHelper.mListener = mListener;
+    protected PagedListAdapter(@NonNull DiffUtil.ItemCallback<T> diffCallback) {
+        mDiffer = new AsyncPagedListDiffer<>(this, diffCallback);
+        mDiffer.mListener = mListener;
     }
 
     @SuppressWarnings("unused, WeakerAccess")
-    protected PagedListAdapter(@NonNull ListAdapterConfig<T> config) {
-        mHelper = new PagedListAdapterHelper<>(new ListAdapterHelper.AdapterCallback(this), config);
-        mHelper.mListener = mListener;
+    protected PagedListAdapter(@NonNull AsyncDifferConfig<T> config) {
+        mDiffer = new AsyncPagedListDiffer<>(new AdapterListUpdateCallback(this), config);
+        mDiffer.mListener = mListener;
     }
 
     /**
@@ -145,38 +147,38 @@
      *
      * @param pagedList The new list to be displayed.
      */
-    public void setList(PagedList<T> pagedList) {
-        mHelper.setList(pagedList);
+    public void submitList(PagedList<T> pagedList) {
+        mDiffer.submitList(pagedList);
     }
 
     @Nullable
     protected T getItem(int position) {
-        return mHelper.getItem(position);
+        return mDiffer.getItem(position);
     }
 
     @Override
     public int getItemCount() {
-        return mHelper.getItemCount();
+        return mDiffer.getItemCount();
     }
 
     /**
-     * Returns the list currently being displayed by the Adapter.
+     * Returns the PagedList currently being displayed by the Adapter.
      * <p>
-     * This is not necessarily the most recent list passed to {@link #setList(PagedList)}, because a
-     * diff is computed asynchronously between the new list and the current list before updating the
-     * currentList value.
+     * This is not necessarily the most recent list passed to {@link #submitList(PagedList)},
+     * because a diff is computed asynchronously between the new list and the current list before
+     * updating the currentList value. May be null if no PagedList is being presented.
      *
      * @return The list currently being displayed.
      */
     @Nullable
     public PagedList<T> getCurrentList() {
-        return mHelper.getCurrentList();
+        return mDiffer.getCurrentList();
     }
 
     /**
      * Called when the current PagedList is updated.
      * <p>
-     * This may be dispatched as part of {@link #setList(PagedList)} if a background diff isn't
+     * This may be dispatched as part of {@link #submitList(PagedList)} if a background diff isn't
      * needed (such as when the first list is passed, or the list is cleared). In either case,
      * PagedListAdapter will simply call
      * {@link #notifyItemRangeInserted(int, int) notifyItemRangeInserted/Removed(0, mPreviousSize)}.
diff --git a/paging/runtime/src/main/java/android/arch/paging/PagedListAdapterHelper.java b/paging/runtime/src/main/java/android/arch/paging/PagedListAdapterHelper.java
deleted file mode 100644
index ba8ffab..0000000
--- a/paging/runtime/src/main/java/android/arch/paging/PagedListAdapterHelper.java
+++ /dev/null
@@ -1,345 +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.arch.paging;
-
-import android.arch.lifecycle.LiveData;
-import android.support.annotation.Nullable;
-import android.support.v7.recyclerview.extensions.DiffCallback;
-import android.support.v7.recyclerview.extensions.ListAdapterConfig;
-import android.support.v7.recyclerview.extensions.ListAdapterHelper;
-import android.support.v7.util.DiffUtil;
-import android.support.v7.util.ListUpdateCallback;
-import android.support.v7.widget.RecyclerView;
-
-/**
- * Helper object for mapping a {@link PagedList} into a
- * {@link android.support.v7.widget.RecyclerView.Adapter RecyclerView.Adapter}.
- * <p>
- * For simplicity, the {@link PagedListAdapter} wrapper class can often be used instead of the
- * helper directly. This helper class is exposed for complex cases, and where overriding an adapter
- * base class to support paging isn't convenient.
- * <p>
- * Both the internal paging of the list as more data is loaded, and updates in the form of new
- * PagedLists.
- * <p>
- * The PagedListAdapterHelper can be bound to a {@link LiveData} of PagedList and present the data
- * simply for an adapter. It listens to PagedList loading callbacks, and uses DiffUtil on a
- * background thread to compute updates as new PagedLists are received.
- * <p>
- * It provides a simple list-like API with {@link #getItem(int)} and {@link #getItemCount()} for an
- * adapter to acquire and present data objects.
- * <p>
- * A complete usage pattern with Room would look like this:
- * <pre>
- * {@literal @}Dao
- * interface UserDao {
- *     {@literal @}Query("SELECT * FROM user ORDER BY lastName ASC")
- *     public abstract DataSource.Factory&lt;Integer, User> usersByLastName();
- * }
- *
- * class MyViewModel extends ViewModel {
- *     public final LiveData&lt;PagedList&lt;User>> usersList;
- *     public MyViewModel(UserDao userDao) {
- *         usersList = new LivePagedListBuilder&lt;>(
- *                 userDao.usersByLastName(), /* page size {@literal *}/ 20).build();
- *     }
- * }
- *
- * class MyActivity extends AppCompatActivity {
- *     {@literal @}Override
- *     public void onCreate(Bundle savedState) {
- *         super.onCreate(savedState);
- *         MyViewModel viewModel = ViewModelProviders.of(this).get(MyViewModel.class);
- *         RecyclerView recyclerView = findViewById(R.id.user_list);
- *         final UserAdapter&lt;User> adapter = new UserAdapter();
- *         viewModel.usersList.observe(this, pagedList -> adapter.setList(pagedList));
- *         recyclerView.setAdapter(adapter);
- *     }
- * }
- *
- * class UserAdapter extends RecyclerView.Adapter&lt;UserViewHolder> {
- *     private final PagedListAdapterHelper&lt;User> mHelper
- *             = new PagedListAdapterHelper(this, DIFF_CALLBACK);
- *     {@literal @}Override
- *     public int getItemCount() {
- *         return mHelper.getItemCount();
- *     }
- *     public void setList(PagedList&lt;User> pagedList) {
- *         mHelper.setList(pagedList);
- *     }
- *     {@literal @}Override
- *     public void onBindViewHolder(UserViewHolder holder, int position) {
- *         User user = mHelper.getItem(position);
- *         if (user != null) {
- *             holder.bindTo(user);
- *         } else {
- *             // Null defines a placeholder item - PagedListAdapterHelper will automatically
- *             // invalidate this row when the actual object is loaded from the database
- *             holder.clear();
- *         }
- *     }
- *     public static final DiffCallback&lt;User> DIFF_CALLBACK = new DiffCallback&lt;User>() {
- *          {@literal @}Override
- *          public boolean areItemsTheSame(
- *                  {@literal @}NonNull User oldUser, {@literal @}NonNull User newUser) {
- *              // User properties may have changed if reloaded from the DB, but ID is fixed
- *              return oldUser.getId() == newUser.getId();
- *          }
- *          {@literal @}Override
- *          public boolean areContentsTheSame(
- *                  {@literal @}NonNull User oldUser, {@literal @}NonNull User newUser) {
- *              // NOTE: if you use equals, your object must properly override Object#equals()
- *              // Incorrectly returning false here will result in too many animations.
- *              return oldUser.equals(newUser);
- *          }
- *      }
- * }</pre>
- *
- * @param <T> Type of the PagedLists this helper will receive.
- */
-public class PagedListAdapterHelper<T> {
-    // updateCallback notifications must only be notified *after* new data and item count are stored
-    // this ensures Adapter#notifyItemRangeInserted etc are accessing the new data
-    private final ListUpdateCallback mUpdateCallback;
-    private final ListAdapterConfig<T> mConfig;
-
-    // TODO: REAL API
-    interface PagedListListener<T> {
-        void onCurrentListChanged(@Nullable PagedList<T> currentList);
-    }
-
-    @Nullable
-    PagedListListener<T> mListener;
-
-    private boolean mIsContiguous;
-
-    private PagedList<T> mPagedList;
-    private PagedList<T> mSnapshot;
-
-    // Max generation of currently scheduled runnable
-    private int mMaxScheduledGeneration;
-
-    /**
-     * Convenience for {@code PagedListAdapterHelper(new ListAdapterHelper.AdapterCallback(adapter),
-     * new ListAdapterConfig.Builder<T>().setDiffCallback(diffCallback).build());
-     *
-     * @param adapter Adapter that will receive update signals.
-     * @param diffCallback The {@link DiffCallback } instance to compare items in the list.
-     */
-    @SuppressWarnings("WeakerAccess")
-    public PagedListAdapterHelper(RecyclerView.Adapter adapter, DiffCallback<T> diffCallback) {
-        mUpdateCallback = new ListAdapterHelper.AdapterCallback(adapter);
-        mConfig = new ListAdapterConfig.Builder<T>().setDiffCallback(diffCallback).build();
-    }
-
-    @SuppressWarnings("WeakerAccess")
-    public PagedListAdapterHelper(ListUpdateCallback listUpdateCallback,
-            ListAdapterConfig<T> config) {
-        mUpdateCallback = listUpdateCallback;
-        mConfig = config;
-    }
-
-    private PagedList.Callback mPagedListCallback = new PagedList.Callback() {
-        @Override
-        public void onInserted(int position, int count) {
-            mUpdateCallback.onInserted(position, count);
-        }
-
-        @Override
-        public void onRemoved(int position, int count) {
-            mUpdateCallback.onRemoved(position, count);
-        }
-
-        @Override
-        public void onChanged(int position, int count) {
-            // NOTE: pass a null payload to convey null -> item
-            mUpdateCallback.onChanged(position, count, null);
-        }
-    };
-
-    /**
-     * Get the item from the current PagedList at the specified index.
-     * <p>
-     * Note that this operates on both loaded items and null padding within the PagedList.
-     *
-     * @param index Index of item to get, must be >= 0, and &lt; {@link #getItemCount()}.
-     * @return The item, or null, if a null placeholder is at the specified position.
-     */
-    @SuppressWarnings("WeakerAccess")
-    @Nullable
-    public T getItem(int index) {
-        if (mPagedList == null) {
-            if (mSnapshot == null) {
-                throw new IndexOutOfBoundsException(
-                        "Item count is zero, getItem() call is invalid");
-            } else {
-                return mSnapshot.get(index);
-            }
-        }
-
-        mPagedList.loadAround(index);
-        return mPagedList.get(index);
-    }
-
-    /**
-     * Get the number of items currently presented by this AdapterHelper. This value can be directly
-     * returned to {@link RecyclerView.Adapter#getItemCount()}.
-     *
-     * @return Number of items being presented.
-     */
-    @SuppressWarnings("WeakerAccess")
-    public int getItemCount() {
-        if (mPagedList != null) {
-            return mPagedList.size();
-        }
-
-        return mSnapshot == null ? 0 : mSnapshot.size();
-    }
-
-    /**
-     * Pass a new PagedList to the AdapterHelper.
-     * <p>
-     * If a PagedList is already present, a diff will be computed asynchronously on a background
-     * thread. When the diff is computed, it will be applied (dispatched to the
-     * {@link ListUpdateCallback}), and the new PagedList will be swapped in.
-     *
-     * @param pagedList The new PagedList.
-     */
-    public void setList(final PagedList<T> pagedList) {
-        if (pagedList != null) {
-            if (mPagedList == null && mSnapshot == null) {
-                mIsContiguous = pagedList.isContiguous();
-            } else {
-                if (pagedList.isContiguous() != mIsContiguous) {
-                    throw new IllegalArgumentException("AdapterHelper cannot handle both contiguous"
-                            + " and non-contiguous lists.");
-                }
-            }
-        }
-
-        if (pagedList == mPagedList) {
-            // nothing to do
-            return;
-        }
-
-        // incrementing generation means any currently-running diffs are discarded when they finish
-        final int runGeneration = ++mMaxScheduledGeneration;
-
-        if (pagedList == null) {
-            int removedCount = getItemCount();
-            if (mPagedList != null) {
-                mPagedList.removeWeakCallback(mPagedListCallback);
-                mPagedList = null;
-            } else if (mSnapshot != null) {
-                mSnapshot = null;
-            }
-            // dispatch update callback after updating mPagedList/mSnapshot
-            mUpdateCallback.onRemoved(0, removedCount);
-            if (mListener != null) {
-                mListener.onCurrentListChanged(null);
-            }
-            return;
-        }
-
-        if (mPagedList == null && mSnapshot == null) {
-            // fast simple first insert
-            mPagedList = pagedList;
-            pagedList.addWeakCallback(null, mPagedListCallback);
-
-            // dispatch update callback after updating mPagedList/mSnapshot
-            mUpdateCallback.onInserted(0, pagedList.size());
-
-            if (mListener != null) {
-                mListener.onCurrentListChanged(pagedList);
-            }
-            return;
-        }
-
-        if (mPagedList != null) {
-            // first update scheduled on this list, so capture mPages as a snapshot, removing
-            // callbacks so we don't have resolve updates against a moving target
-            mPagedList.removeWeakCallback(mPagedListCallback);
-            mSnapshot = (PagedList<T>) mPagedList.snapshot();
-            mPagedList = null;
-        }
-
-        if (mSnapshot == null || mPagedList != null) {
-            throw new IllegalStateException("must be in snapshot state to diff");
-        }
-
-        final PagedList<T> oldSnapshot = mSnapshot;
-        final PagedList<T> newSnapshot = (PagedList<T>) pagedList.snapshot();
-        mConfig.getBackgroundThreadExecutor().execute(new Runnable() {
-            @Override
-            public void run() {
-                final DiffUtil.DiffResult result;
-                result = PagedStorageDiffHelper.computeDiff(
-                        oldSnapshot.mStorage,
-                        newSnapshot.mStorage,
-                        mConfig.getDiffCallback());
-
-                mConfig.getMainThreadExecutor().execute(new Runnable() {
-                    @Override
-                    public void run() {
-                        if (mMaxScheduledGeneration == runGeneration) {
-                            latchPagedList(pagedList, newSnapshot, result);
-                        }
-                    }
-                });
-            }
-        });
-    }
-
-    private void latchPagedList(
-            PagedList<T> newList, PagedList<T> diffSnapshot,
-            DiffUtil.DiffResult diffResult) {
-        if (mSnapshot == null || mPagedList != null) {
-            throw new IllegalStateException("must be in snapshot state to apply diff");
-        }
-
-        PagedList<T> previousSnapshot = mSnapshot;
-        mPagedList = newList;
-        mSnapshot = null;
-
-        // dispatch update callback after updating mPagedList/mSnapshot
-        PagedStorageDiffHelper.dispatchDiff(mUpdateCallback,
-                previousSnapshot.mStorage, newList.mStorage, diffResult);
-
-        newList.addWeakCallback(diffSnapshot, mPagedListCallback);
-        if (mListener != null) {
-            mListener.onCurrentListChanged(mPagedList);
-        }
-    }
-
-    /**
-     * Returns the list currently being displayed by the AdapterHelper.
-     * <p>
-     * This is not necessarily the most recent list passed to {@link #setList(PagedList)}, because a
-     * diff is computed asynchronously between the new list and the current list before updating the
-     * currentList value.
-     *
-     * @return The list currently being displayed.
-     */
-    @SuppressWarnings("WeakerAccess")
-    @Nullable
-    public PagedList<T> getCurrentList() {
-        if (mSnapshot != null) {
-            return mSnapshot;
-        }
-        return mPagedList;
-    }
-}
diff --git a/paging/runtime/src/main/java/android/arch/paging/PagedStorageDiffHelper.java b/paging/runtime/src/main/java/android/arch/paging/PagedStorageDiffHelper.java
index d991b72..f495608 100644
--- a/paging/runtime/src/main/java/android/arch/paging/PagedStorageDiffHelper.java
+++ b/paging/runtime/src/main/java/android/arch/paging/PagedStorageDiffHelper.java
@@ -17,7 +17,6 @@
 package android.arch.paging;
 
 import android.support.annotation.Nullable;
-import android.support.v7.recyclerview.extensions.DiffCallback;
 import android.support.v7.util.DiffUtil;
 import android.support.v7.util.ListUpdateCallback;
 
@@ -28,7 +27,7 @@
     static <T> DiffUtil.DiffResult computeDiff(
             final PagedStorage<T> oldList,
             final PagedStorage<T> newList,
-            final DiffCallback<T> diffCallback) {
+            final DiffUtil.ItemCallback<T> diffCallback) {
         final int oldOffset = oldList.computeLeadingNulls();
         final int newOffset = newList.computeLeadingNulls();
 
diff --git a/paging/runtime/src/main/java/android/support/v7/recyclerview/extensions/DiffCallback.java b/paging/runtime/src/main/java/android/support/v7/recyclerview/extensions/DiffCallback.java
index 70fc049..2083a5f 100644
--- a/paging/runtime/src/main/java/android/support/v7/recyclerview/extensions/DiffCallback.java
+++ b/paging/runtime/src/main/java/android/support/v7/recyclerview/extensions/DiffCallback.java
@@ -16,50 +16,21 @@
 
 package android.support.v7.recyclerview.extensions;
 
-import android.arch.paging.PagedListAdapterHelper;
-import android.support.annotation.NonNull;
+import android.arch.paging.AsyncPagedListDiffer;
+import android.support.v7.util.DiffUtil;
 
 /**
- * Callback that informs {@link PagedListAdapterHelper} how to compute list updates when using
+ * Callback that informs {@link AsyncPagedListDiffer} how to compute list updates when using
  * {@link android.support.v7.util.DiffUtil} on a background thread.
  * <p>
  * The AdapterHelper will pass items from different lists to this callback in order to implement
  * the {@link android.support.v7.util.DiffUtil.Callback} it uses to compute differences between
  * lists.
- * <p>
- * Note that this class is likely to move prior to the final release of the Paging library.
  *
  * @param <T> Type of items to compare.
+ *
+ * @deprecated use {@link DiffUtil.ItemCallback DiffUtil.ItemCallback} directly starting in 27.1.0
  */
-public abstract class DiffCallback<T> {
-    /**
-     * Called to decide whether two objects represent the same item.
-     *
-     * @param oldItem The item in the old list.
-     * @param newItem The item in the new list.
-     * @return True if the two items represent the same object or false if they are different.
-     * @see android.support.v7.util.DiffUtil.Callback#areItemsTheSame(int, int)
-     */
-    public abstract boolean areItemsTheSame(@NonNull T oldItem, @NonNull T newItem);
-
-    /**
-     * Called to decide whether two items have the same data. This information is used to detect if
-     * the contents of an item have changed.
-     *
-     * @param oldItem The item in the old list.
-     * @param newItem The item in the new list.
-     * @return True if the contents of the items are the same or false if they are different.
-     * @see android.support.v7.util.DiffUtil.Callback#areContentsTheSame(int, int)
-     */
-    public abstract boolean areContentsTheSame(@NonNull T oldItem, @NonNull T newItem);
-
-    /**
-     * Called to get a change payload between an old and new version of an item.
-     *
-     * @see android.support.v7.util.DiffUtil.Callback#getChangePayload(int, int)
-     */
-    @SuppressWarnings("WeakerAccess")
-    public Object getChangePayload(@NonNull T oldItem, @NonNull T newItem) {
-        return null;
-    }
+@Deprecated
+public abstract class DiffCallback<T> extends DiffUtil.ItemCallback<T> {
 }
diff --git a/paging/runtime/src/main/java/android/support/v7/recyclerview/extensions/ListAdapter.java b/paging/runtime/src/main/java/android/support/v7/recyclerview/extensions/ListAdapter.java
deleted file mode 100644
index 8b28072..0000000
--- a/paging/runtime/src/main/java/android/support/v7/recyclerview/extensions/ListAdapter.java
+++ /dev/null
@@ -1,129 +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.annotation.NonNull;
-import android.support.v7.widget.RecyclerView;
-
-import java.util.List;
-
-/**
- * {@link RecyclerView.Adapter RecyclerView.Adapter} base class for presenting List data in a
- * {@link RecyclerView}, including computing diffs between Lists on a background thread.
- * <p>
- * This class is a convenience wrapper around ListAdapterHelper that implements common default
- * behavior for item access and counting.
- * <p>
- * While using a LiveData&lt;List> is an easy way to provide data to the adapter, it isn't required
- * - you can use {@link #setList(List)} when new lists are available.
- * <p>
- * A complete usage pattern with Room would look like this:
- * <pre>
- * {@literal @}Dao
- * interface UserDao {
- *     {@literal @}Query("SELECT * FROM user ORDER BY lastName ASC")
- *     public abstract LiveData&lt;List&lt;User>> usersByLastName();
- * }
- *
- * class MyViewModel extends ViewModel {
- *     public final LiveData&lt;List&lt;User>> usersList;
- *     public MyViewModel(UserDao userDao) {
- *         usersList = userDao.usersByLastName();
- *     }
- * }
- *
- * class MyActivity extends AppCompatActivity {
- *     {@literal @}Override
- *     public void onCreate(Bundle savedState) {
- *         super.onCreate(savedState);
- *         MyViewModel viewModel = ViewModelProviders.of(this).get(MyViewModel.class);
- *         RecyclerView recyclerView = findViewById(R.id.user_list);
- *         UserAdapter&lt;User> adapter = new UserAdapter();
- *         viewModel.usersList.observe(this, list -> adapter.setList(list));
- *         recyclerView.setAdapter(adapter);
- *     }
- * }
- *
- * class UserAdapter extends ListAdapter&lt;User, UserViewHolder> {
- *     public UserAdapter() {
- *         super(User.DIFF_CALLBACK);
- *     }
- *     {@literal @}Override
- *     public void onBindViewHolder(UserViewHolder holder, int position) {
- *         holder.bindTo(getItem(position));
- *     }
- *     public static final DiffCallback&lt;User> DIFF_CALLBACK = new DiffCallback&lt;User>() {
- *         {@literal @}Override
- *         public boolean areItemsTheSame(
- *                 {@literal @}NonNull User oldUser, {@literal @}NonNull User newUser) {
- *             // User properties may have changed if reloaded from the DB, but ID is fixed
- *             return oldUser.getId() == newUser.getId();
- *         }
- *         {@literal @}Override
- *         public boolean areContentsTheSame(
- *                 {@literal @}NonNull User oldUser, {@literal @}NonNull User newUser) {
- *             // NOTE: if you use equals, your object must properly override Object#equals()
- *             // Incorrectly returning false here will result in too many animations.
- *             return oldUser.equals(newUser);
- *         }
- *     }
- * }</pre>
- *
- * Advanced users that wish for more control over adapter behavior, or to provide a specific base
- * class should refer to {@link ListAdapterHelper}, which provides custom mapping from diff events
- * to adapter positions.
- *
- * @param <T> Type of the Lists this Adapter will receive.
- * @param <VH> A class that extends ViewHolder that will be used by the adapter.
- */
-public abstract class ListAdapter<T, VH extends RecyclerView.ViewHolder>
-        extends RecyclerView.Adapter<VH> {
-    private final ListAdapterHelper<T> mHelper;
-
-    @SuppressWarnings("unused")
-    protected ListAdapter(@NonNull DiffCallback<T> diffCallback) {
-        mHelper = new ListAdapterHelper<>(new ListAdapterHelper.AdapterCallback(this),
-                new ListAdapterConfig.Builder<T>().setDiffCallback(diffCallback).build());
-    }
-
-    @SuppressWarnings("unused")
-    protected ListAdapter(@NonNull ListAdapterConfig<T> config) {
-        mHelper = new ListAdapterHelper<>(new ListAdapterHelper.AdapterCallback(this), config);
-    }
-
-    /**
-     * Set the new list to be displayed.
-     * <p>
-     * If a list is already being displayed, a diff will be computed on a background thread, which
-     * will dispatch Adapter.notifyItem events on the main thread.
-     *
-     * @param list The new list to be displayed.
-     */
-    public void setList(List<T> list) {
-        mHelper.setList(list);
-    }
-
-    @SuppressWarnings("unused")
-    protected T getItem(int position) {
-        return mHelper.getItem(position);
-    }
-
-    @Override
-    public int getItemCount() {
-        return mHelper.getItemCount();
-    }
-}
diff --git a/paging/runtime/src/main/java/android/support/v7/recyclerview/extensions/ListAdapterConfig.java b/paging/runtime/src/main/java/android/support/v7/recyclerview/extensions/ListAdapterConfig.java
index 25697a1..13036a7 100644
--- a/paging/runtime/src/main/java/android/support/v7/recyclerview/extensions/ListAdapterConfig.java
+++ b/paging/runtime/src/main/java/android/support/v7/recyclerview/extensions/ListAdapterConfig.java
@@ -17,25 +17,35 @@
 package android.support.v7.recyclerview.extensions;
 
 import android.arch.core.executor.ArchTaskExecutor;
+import android.support.v7.util.DiffUtil;
 
 import java.util.concurrent.Executor;
 
 /**
- * Configuration object for {@link ListAdapter}, {@link ListAdapterHelper}, and similar
+ * Configuration object for {@link ListAdapterHelper}, and similar
  * background-thread list diffing adapter logic.
  * <p>
- * At minimum, defines item diffing behavior with a {@link DiffCallback}, used to compute item
- * differences to pass to a RecyclerView adapter.
+ * At minimum, defines item diffing behavior with a {@link DiffUtil.ItemCallback}, used to compute
+ * item differences to pass to a RecyclerView adapter.
  *
- * @param <T> Type of items in the lists, and being compared.
+ * @param <T> List item type being compared by the {@link DiffUtil.ItemCallback}.
+ *
+ * @deprecated use {@link android.support.v7.recyclerview.extensions.AsyncDifferConfig} in the
+ * RecyclerView module, starting in 27.1.0. It can be used with
+ * {@link android.support.v7.recyclerview.extensions.ListAdapter} and
+ * {@link android.support.v7.recyclerview.extensions.AsyncListDiffer} in the recyclerview module, as
+ * well as {@link android.arch.paging.PagedListAdapter} and
+ * {@link android.arch.paging.AsyncPagedListDiffer} in the paging library. It is being moved from
+ * the Paging Library to RecyclerView since it is useful independent of paging.
  */
+@Deprecated
 public final class ListAdapterConfig<T> {
     private final Executor mMainThreadExecutor;
     private final Executor mBackgroundThreadExecutor;
-    private final DiffCallback<T> mDiffCallback;
+    private final DiffUtil.ItemCallback<T> mDiffCallback;
 
     private ListAdapterConfig(Executor mainThreadExecutor, Executor backgroundThreadExecutor,
-            DiffCallback<T> diffCallback) {
+            DiffUtil.ItemCallback<T> diffCallback) {
         mMainThreadExecutor = mainThreadExecutor;
         mBackgroundThreadExecutor = backgroundThreadExecutor;
         mDiffCallback = diffCallback;
@@ -49,31 +59,33 @@
         return mBackgroundThreadExecutor;
     }
 
-    public DiffCallback<T> getDiffCallback() {
+    public DiffUtil.ItemCallback<T> getDiffCallback() {
         return mDiffCallback;
     }
 
     /**
      * Builder class for {@link ListAdapterConfig}.
      * <p>
-     * You must at minimum specify a DiffCallback with {@link #setDiffCallback(DiffCallback)}
+     * You must at minimum specify a DiffUtil.ItemCallback with
+     * {@link #setDiffCallback(DiffUtil.ItemCallback)}
      *
      * @param <T>
      */
     public static class Builder<T> {
         private Executor mMainThreadExecutor;
         private Executor mBackgroundThreadExecutor;
-        private DiffCallback<T> mDiffCallback;
+        private DiffUtil.ItemCallback<T> mDiffCallback;
 
         /**
-         * The {@link DiffCallback} to be used while diffing an old list with the updated one.
-         * Must be provided.
+         * The {@link DiffUtil.ItemCallback} to be used while diffing an old list with the updated
+         * one. Must be provided.
          *
-         * @param diffCallback The {@link DiffCallback} instance to compare items in the list.
+         * @param diffCallback The {@link DiffUtil.ItemCallback} instance to compare items in the
+         *                     list.
          * @return this
          */
         @SuppressWarnings("WeakerAccess")
-        public ListAdapterConfig.Builder<T> setDiffCallback(DiffCallback<T> diffCallback) {
+        public ListAdapterConfig.Builder<T> setDiffCallback(DiffUtil.ItemCallback<T> diffCallback) {
             mDiffCallback = diffCallback;
             return this;
         }
diff --git a/paging/runtime/src/main/java/android/support/v7/recyclerview/extensions/ListAdapterHelper.java b/paging/runtime/src/main/java/android/support/v7/recyclerview/extensions/ListAdapterHelper.java
index 0c7806f..81d8a20 100644
--- a/paging/runtime/src/main/java/android/support/v7/recyclerview/extensions/ListAdapterHelper.java
+++ b/paging/runtime/src/main/java/android/support/v7/recyclerview/extensions/ListAdapterHelper.java
@@ -17,21 +17,19 @@
 package android.support.v7.recyclerview.extensions;
 
 import android.arch.lifecycle.LiveData;
-import android.support.annotation.RestrictTo;
 import android.support.v7.util.DiffUtil;
 import android.support.v7.util.ListUpdateCallback;
-import android.support.v7.widget.RecyclerView;
 
 import java.util.List;
 
 /**
- * Helper object for displaying a List in {@link RecyclerView.Adapter RecyclerView.Adapter}, which
- * signals the adapter of changes when the List is changed by computing changes with DiffUtil in the
- * background.
+ * Helper object for displaying a List in {@link android.support.v7.widget.RecyclerView.Adapter
+ * RecyclerView.Adapter}, which signals the adapter of changes when the List is changed by computing
+ * changes with DiffUtil in the background.
  * <p>
- * For simplicity, the {@link ListAdapter} wrapper class can often be used instead of the
- * helper directly. This helper class is exposed for complex cases, and where overriding an adapter
- * base class to support List diffing isn't convenient.
+ * For simplicity, the {@link android.support.v7.recyclerview.extensions.ListAdapter} wrapper class
+ * can often be used instead of the helper directly. This helper class is exposed for complex cases,
+ * and where overriding an adapter base class to support List diffing isn't convenient.
  * <p>
  * The ListAdapterHelper can take a {@link LiveData} of List and present the data simply for an
  * adapter. It computes differences in List contents via DiffUtil on a background thread as new
@@ -39,68 +37,13 @@
  * <p>
  * It provides a simple list-like API with {@link #getItem(int)} and {@link #getItemCount()} for an
  * adapter to acquire and present data objects.
- * <p>
- * A complete usage pattern with Room would look like this:
- * <pre>
- * {@literal @}Dao
- * interface UserDao {
- *     {@literal @}Query("SELECT * FROM user ORDER BY lastName ASC")
- *     public abstract LiveData&lt;List&lt;User>> usersByLastName();
- * }
- *
- * class MyViewModel extends ViewModel {
- *     public final LiveData&lt;List&lt;User>> usersList;
- *     public MyViewModel(UserDao userDao) {
- *         usersList = userDao.usersByLastName();
- *     }
- * }
- *
- * class MyActivity extends AppCompatActivity {
- *     {@literal @}Override
- *     public void onCreate(Bundle savedState) {
- *         super.onCreate(savedState);
- *         MyViewModel viewModel = ViewModelProviders.of(this).get(MyViewModel.class);
- *         RecyclerView recyclerView = findViewById(R.id.user_list);
- *         UserAdapter&lt;User> adapter = new UserAdapter();
- *         viewModel.usersList.observe(this, list -> adapter.setList(list));
- *         recyclerView.setAdapter(adapter);
- *     }
- * }
- *
- * class UserAdapter extends RecyclerView.Adapter&lt;UserViewHolder> {
- *     private final ListAdapterHelper&lt;User> mHelper
- *             = new ListAdapterHelper(this, User.DIFF_CALLBACK);
- *     {@literal @}Override
- *     public int getItemCount() {
- *         return mHelper.getItemCount();
- *     }
- *     public void setList(List&lt;User> list) {
- *         mHelper.setList(list);
- *     }
- *     {@literal @}Override
- *     public void onBindViewHolder(UserViewHolder holder, int position) {
- *         User user = mHelper.getItem(position);
- *         holder.bindTo(user);
- *     }
- *     public static final DiffCallback&lt;User> DIFF_CALLBACK = new DiffCallback&lt;User>() {
- *         {@literal @}Override
- *         public boolean areItemsTheSame(
- *                 {@literal @}NonNull User oldUser, {@literal @}NonNull User newUser) {
- *             // User properties may have changed if reloaded from the DB, but ID is fixed
- *             return oldUser.getId() == newUser.getId();
- *         }
- *         {@literal @}Override
- *         public boolean areContentsTheSame(
- *                 {@literal @}NonNull User oldUser, {@literal @}NonNull User newUser) {
- *             // NOTE: if you use equals, your object must properly override Object#equals()
- *             // Incorrectly returning false here will result in too many animations.
- *             return oldUser.equals(newUser);
- *         }
- *     }
- * }</pre>
  *
  * @param <T> Type of the lists this helper will receive.
+ * @deprecated use {@link android.support.v7.recyclerview.extensions.AsyncListDiffer} in the
+ * RecyclerView module, starting in 27.1.0. It is being moved from the Paging Library to
+ * RecyclerView since it is useful independent of paging.
  */
+@Deprecated
 public class ListAdapterHelper<T> {
     private final ListUpdateCallback mUpdateCallback;
     private final ListAdapterConfig<T> mConfig;
@@ -112,42 +55,6 @@
         mConfig = config;
     }
 
-    /**
-     * Default ListUpdateCallback that dispatches directly to an adapter. Can be replaced by a
-     * custom ListUpdateCallback if e.g. your adapter has a header in it, and so has an offset
-     * between list positions and adapter positions.
-     *
-     * @hide
-     */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-    public static class AdapterCallback implements ListUpdateCallback {
-        private final RecyclerView.Adapter mAdapter;
-
-        public AdapterCallback(RecyclerView.Adapter adapter) {
-            mAdapter = adapter;
-        }
-
-        @Override
-        public void onInserted(int position, int count) {
-            mAdapter.notifyItemRangeInserted(position, count);
-        }
-
-        @Override
-        public void onRemoved(int position, int count) {
-            mAdapter.notifyItemRangeRemoved(position, count);
-        }
-
-        @Override
-        public void onMoved(int fromPosition, int toPosition) {
-            mAdapter.notifyItemMoved(fromPosition, toPosition);
-        }
-
-        @Override
-        public void onChanged(int position, int count, Object payload) {
-            mAdapter.notifyItemRangeChanged(position, count, payload);
-        }
-    }
-
     private List<T> mList;
 
     // Max generation of currently scheduled runnable
@@ -171,7 +78,7 @@
 
     /**
      * Get the number of items currently presented by this AdapterHelper. This value can be directly
-     * returned to {@link RecyclerView.Adapter#getItemCount()}.
+     * returned to {@link android.support.v7.widget.RecyclerView.Adapter#getItemCount()}.
      *
      * @return Number of items being presented.
      */
diff --git a/pathmap.mk b/pathmap.mk
index a71eb54..ebc023e 100644
--- a/pathmap.mk
+++ b/pathmap.mk
@@ -29,6 +29,7 @@
     android-support-dynamic-animation \
     android-support-exifinterface \
     android-support-fragment \
+    android-support-heifwriter \
     android-support-media-compat \
     android-support-percent \
     android-support-recommendation \
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/AndroidManifest.xml b/percent/src/main/AndroidManifest.xml
similarity index 100%
rename from percent/AndroidManifest.xml
rename to percent/src/main/AndroidManifest.xml
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/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/AndroidManifest.xml b/preference-leanback/src/main/AndroidManifest.xml
similarity index 100%
rename from preference-leanback/AndroidManifest.xml
rename to preference-leanback/src/main/AndroidManifest.xml
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/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/AndroidManifest.xml b/recommendation/src/main/AndroidManifest.xml
similarity index 100%
rename from recommendation/AndroidManifest.xml
rename to recommendation/src/main/AndroidManifest.xml
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/tests/AndroidManifest.xml b/recyclerview-selection/src/androidTest/AndroidManifest.xml
similarity index 100%
rename from recyclerview-selection/tests/AndroidManifest.xml
rename to recyclerview-selection/src/androidTest/AndroidManifest.xml
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/AndroidManifest.xml b/recyclerview-selection/src/main/AndroidManifest.xml
similarity index 100%
rename from recyclerview-selection/AndroidManifest.xml
rename to recyclerview-selection/src/main/AndroidManifest.xml
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/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/room/compiler/src/main/kotlin/android/arch/persistence/room/ext/element_ext.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/ext/element_ext.kt
index 44800fc..fbd54c4 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/ext/element_ext.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/ext/element_ext.kt
@@ -21,6 +21,7 @@
 import com.google.auto.common.AnnotationMirrors
 import com.google.auto.common.MoreElements
 import com.google.auto.common.MoreTypes
+import org.jetbrains.kotlin.load.java.JvmAbi
 import javax.annotation.processing.ProcessingEnvironment
 import javax.lang.model.element.AnnotationValue
 import javax.lang.model.element.Element
@@ -210,4 +211,32 @@
             return type.extendsBound
         }
     }, null)
-}
\ No newline at end of file
+}
+
+/**
+ * Finds the default implementation method corresponding to this Kotlin interface method.
+ */
+fun Element.findKotlinDefaultImpl(typeUtils: Types): Element? {
+    fun paramsMatch(ourParams: List<VariableElement>, theirParams: List<VariableElement>): Boolean {
+        if (ourParams.size != theirParams.size - 1) {
+            return false
+        }
+        ourParams.forEachIndexed { i, variableElement ->
+            // Plus 1 to their index because their first param is a self object.
+            if (!typeUtils.isSameType(theirParams[i + 1].asType(), variableElement.asType())) {
+                return false
+            }
+        }
+        return true
+    }
+
+    val parent = this.enclosingElement as TypeElement
+    val innerClass = parent.enclosedElements.find {
+        it.kind == ElementKind.CLASS && it.simpleName.contentEquals(JvmAbi.DEFAULT_IMPLS_CLASS_NAME)
+    } ?: return null
+    return innerClass.enclosedElements.find {
+        it.kind == ElementKind.METHOD && it.simpleName == this.simpleName
+                && paramsMatch(MoreElements.asExecutable(this).parameters,
+                MoreElements.asExecutable(it).parameters)
+    }
+}
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/ext/javapoet_ext.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/ext/javapoet_ext.kt
index acc3111..5ad8c35 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/ext/javapoet_ext.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/ext/javapoet_ext.kt
@@ -123,6 +123,10 @@
     val OPTIONAL = ClassName.get("com.google.common.base", "Optional")
 }
 
+object GuavaUtilConcurrentTypeNames {
+    val LISTENABLE_FUTURE = ClassName.get("com.google.common.util.concurrent", "ListenableFuture")
+}
+
 object RxJava2TypeNames {
     val FLOWABLE = ClassName.get("io.reactivex", "Flowable")
     val MAYBE = ClassName.get("io.reactivex", "Maybe")
@@ -133,6 +137,10 @@
     val PUBLISHER = ClassName.get("org.reactivestreams", "Publisher")
 }
 
+object RoomGuavaTypeNames {
+    val GUAVA_ROOM = ClassName.get("android.arch.persistence.room.guava", "GuavaRoom")
+}
+
 object RoomRxJava2TypeNames {
     val RX_ROOM = ClassName.get("android.arch.persistence.room", "RxRoom")
     val RX_EMPTY_RESULT_SET_EXCEPTION = ClassName.get("android.arch.persistence.room",
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/parser/SqlParser.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/parser/SqlParser.kt
index 0bd2f49..0114a83 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/parser/SqlParser.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/parser/SqlParser.kt
@@ -116,14 +116,17 @@
 
     private fun unescapeIdentifier(text: String): String {
         val trimmed = text.trim()
-        if (trimmed.startsWith("`") && trimmed.endsWith('`')) {
-            return unescapeIdentifier(trimmed.substring(1, trimmed.length - 1))
-        }
-        if (trimmed.startsWith('"') && trimmed.endsWith('"')) {
-            return unescapeIdentifier(trimmed.substring(1, trimmed.length - 1))
+        ESCAPE_LITERALS.forEach {
+            if (trimmed.startsWith(it) && trimmed.endsWith(it)) {
+                return unescapeIdentifier(trimmed.substring(1, trimmed.length - 1))
+            }
         }
         return trimmed
     }
+
+    companion object {
+        private val ESCAPE_LITERALS = listOf("\"", "'", "`")
+    }
 }
 
 class SqlParser {
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/DaoProcessor.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/DaoProcessor.kt
index f0aa974..0a622c9 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/DaoProcessor.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/DaoProcessor.kt
@@ -23,6 +23,7 @@
 import android.arch.persistence.room.SkipQueryVerification
 import android.arch.persistence.room.Transaction
 import android.arch.persistence.room.Update
+import android.arch.persistence.room.ext.findKotlinDefaultImpl
 import android.arch.persistence.room.ext.hasAnnotation
 import android.arch.persistence.room.ext.hasAnyOf
 import android.arch.persistence.room.ext.typeName
@@ -57,6 +58,7 @@
         val methods = allMembers
             .filter {
                 it.hasAnyOf(ABSTRACT) && it.kind == ElementKind.METHOD
+                        && it.findKotlinDefaultImpl(context.processingEnv.typeUtils) == null
             }.map {
                 MoreElements.asExecutable(it)
             }.groupBy { method ->
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/EntityProcessor.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/EntityProcessor.kt
index fc0df44..313f968 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/EntityProcessor.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/EntityProcessor.kt
@@ -49,7 +49,7 @@
 
 class EntityProcessor(baseContext: Context,
                       val element: TypeElement,
-                      val referenceStack: LinkedHashSet<Name> = LinkedHashSet<Name>()) {
+                      private val referenceStack: LinkedHashSet<Name> = LinkedHashSet()) {
     val context = baseContext.fork(element)
 
     fun process(): Entity {
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/PojoMethodProcessor.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/PojoMethodProcessor.kt
new file mode 100644
index 0000000..e08b816
--- /dev/null
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/PojoMethodProcessor.kt
@@ -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 android.arch.persistence.room.processor
+
+import android.arch.persistence.room.vo.PojoMethod
+import com.google.auto.common.MoreTypes
+import javax.lang.model.element.ExecutableElement
+import javax.lang.model.type.DeclaredType
+
+/**
+ * processes an executable element as member of the owning class
+ */
+class PojoMethodProcessor(
+        private val context: Context,
+        private val element: ExecutableElement,
+        private val owner: DeclaredType) {
+    fun process(): PojoMethod {
+        val asMember = context.processingEnv.typeUtils.asMemberOf(owner, element)
+        val name = element.simpleName.toString()
+        return PojoMethod(
+                element = element,
+                resolvedType = MoreTypes.asExecutable(asMember),
+                name = name
+        )
+    }
+}
\ No newline at end of file
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/PojoProcessor.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/PojoProcessor.kt
index 3d73948..d5cd8d2 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/PojoProcessor.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/PojoProcessor.kt
@@ -43,6 +43,7 @@
 import android.arch.persistence.room.vo.FieldGetter
 import android.arch.persistence.room.vo.FieldSetter
 import android.arch.persistence.room.vo.Pojo
+import android.arch.persistence.room.vo.PojoMethod
 import android.arch.persistence.room.vo.Warning
 import com.google.auto.common.AnnotationMirrors
 import com.google.auto.common.MoreElements
@@ -72,11 +73,12 @@
 /**
  * Processes any class as if it is a Pojo.
  */
-class PojoProcessor(baseContext: Context,
-                    val element: TypeElement,
-                    val bindingScope: FieldProcessor.BindingScope,
-                    val parent: EmbeddedField?,
-                    val referenceStack: LinkedHashSet<Name> = LinkedHashSet())
+class PojoProcessor(
+        baseContext: Context,
+        val element: TypeElement,
+        val bindingScope: FieldProcessor.BindingScope,
+        val parent: EmbeddedField?,
+        val referenceStack: LinkedHashSet<Name> = LinkedHashSet())
     : KotlinMetadataUtils {
     val context = baseContext.fork(element)
 
@@ -184,13 +186,20 @@
                             && !it.hasAnnotation(Ignore::class)
                 }
                 .map { MoreElements.asExecutable(it) }
+                .map {
+                    PojoMethodProcessor(
+                            context = context,
+                            element = it,
+                            owner = declaredType
+                    ).process()
+                }
 
         val getterCandidates = methods.filter {
-            it.parameters.size == 0 && it.returnType.kind != TypeKind.VOID
+            it.element.parameters.size == 0 && it.resolvedType.returnType.kind != TypeKind.VOID
         }
 
         val setterCandidates = methods.filter {
-            it.parameters.size == 1 && it.returnType.kind == TypeKind.VOID
+            it.element.parameters.size == 1 && it.resolvedType.returnType.kind == TypeKind.VOID
         }
 
         // don't try to find a constructor for binding to statement.
@@ -267,6 +276,9 @@
         val typeUtils = context.processingEnv.typeUtils
         // list of param names -> matched params pairs for each failed constructor
         val failedConstructors = arrayListOf<FailedConstructor>()
+        // if developer puts a relation into a constructor, it is usually an error but if there
+        // is another constructor that is good, we can ignore the error. b/72884434
+        val relationsInConstructor = arrayListOf<VariableElement>()
         val goodConstructors = constructors.map { constructor ->
             val parameterNames = getParamNames(constructor)
             val params = constructor.parameters.mapIndexed param@ { index, param ->
@@ -307,8 +319,7 @@
                         it.field.nameWithVariations.contains(paramName)
                     }
                     if (matchedRelation) {
-                        context.logger.e(param,
-                                ProcessorErrors.RELATION_CANNOT_BE_CONSTRUCTOR_PARAMETER)
+                        relationsInConstructor.add(param)
                     }
                     null
                 } else if (matchingFields.size + embeddedMatches.size == 1) {
@@ -335,31 +346,38 @@
                 Constructor(constructor, params as List<Constructor.Param>)
             }
         }.filterNotNull()
-        if (goodConstructors.isEmpty()) {
-            if (failedConstructors.isNotEmpty()) {
-                val failureMsg = failedConstructors.joinToString("\n") { entry ->
-                    entry.log()
+        when {
+            goodConstructors.isEmpty() -> {
+                relationsInConstructor.forEach {
+                    context.logger.e(it,
+                            ProcessorErrors.RELATION_CANNOT_BE_CONSTRUCTOR_PARAMETER)
                 }
-                context.logger.e(element, ProcessorErrors.MISSING_POJO_CONSTRUCTOR +
-                        "\nTried the following constructors but they failed to match:\n$failureMsg")
+                if (failedConstructors.isNotEmpty()) {
+                    val failureMsg = failedConstructors.joinToString("\n") { entry ->
+                        entry.log()
+                    }
+                    context.logger.e(element, ProcessorErrors.MISSING_POJO_CONSTRUCTOR +
+                            "\nTried the following constructors but they failed to match:" +
+                            "\n$failureMsg")
+                }
+                context.logger.e(element, ProcessorErrors.MISSING_POJO_CONSTRUCTOR)
+                return null
             }
-            context.logger.e(element, ProcessorErrors.MISSING_POJO_CONSTRUCTOR)
-            return null
-        } else if (goodConstructors.size > 1) {
-            // if there is a no-arg constructor, pick it. Even though it is weird, easily happens
-            // with kotlin data classes.
-            val noArg = goodConstructors.firstOrNull { it.params.isEmpty() }
-            if (noArg != null) {
-                context.logger.w(Warning.DEFAULT_CONSTRUCTOR, element,
-                        ProcessorErrors.TOO_MANY_POJO_CONSTRUCTORS_CHOOSING_NO_ARG)
-                return noArg
+            goodConstructors.size > 1 -> {
+                // if there is a no-arg constructor, pick it. Even though it is weird, easily happens
+                // with kotlin data classes.
+                val noArg = goodConstructors.firstOrNull { it.params.isEmpty() }
+                if (noArg != null) {
+                    context.logger.w(Warning.DEFAULT_CONSTRUCTOR, element,
+                            ProcessorErrors.TOO_MANY_POJO_CONSTRUCTORS_CHOOSING_NO_ARG)
+                    return noArg
+                }
+                goodConstructors.forEach {
+                    context.logger.e(it.element, ProcessorErrors.TOO_MANY_POJO_CONSTRUCTORS)
+                }
+                return null
             }
-            goodConstructors.forEach {
-                context.logger.e(it.element, ProcessorErrors.TOO_MANY_POJO_CONSTRUCTORS)
-            }
-            return null
-        } else {
-            return goodConstructors.first()
+            else -> return goodConstructors.first()
         }
     }
 
@@ -576,18 +594,18 @@
         return referenceRecursionList.joinToString(" -> ")
     }
 
-    private fun assignGetters(fields: List<Field>, getterCandidates: List<ExecutableElement>) {
+    private fun assignGetters(fields: List<Field>, getterCandidates: List<PojoMethod>) {
         fields.forEach { field ->
             assignGetter(field, getterCandidates)
         }
     }
 
-    private fun assignGetter(field: Field, getterCandidates: List<ExecutableElement>) {
+    private fun assignGetter(field: Field, getterCandidates: List<PojoMethod>) {
         val success = chooseAssignment(field = field,
                 candidates = getterCandidates,
                 nameVariations = field.getterNameWithVariations,
                 getType = { method ->
-                    method.returnType
+                    method.resolvedType.returnType
                 },
                 assignFromField = {
                     field.getter = FieldGetter(
@@ -597,8 +615,8 @@
                 },
                 assignFromMethod = { match ->
                     field.getter = FieldGetter(
-                            name = match.simpleName.toString(),
-                            type = match.returnType,
+                            name = match.name,
+                            type = match.resolvedType.returnType,
                             callType = CallType.METHOD)
                 },
                 reportAmbiguity = { matching ->
@@ -608,15 +626,19 @@
         context.checker.check(success, field.element, CANNOT_FIND_GETTER_FOR_FIELD)
     }
 
-    private fun assignSetters(fields: List<Field>, setterCandidates: List<ExecutableElement>,
-                              constructor: Constructor?) {
+    private fun assignSetters(
+            fields: List<Field>,
+            setterCandidates: List<PojoMethod>,
+            constructor: Constructor?) {
         fields.forEach { field ->
             assignSetter(field, setterCandidates, constructor)
         }
     }
 
-    private fun assignSetter(field: Field, setterCandidates: List<ExecutableElement>,
-                             constructor: Constructor?) {
+    private fun assignSetter(
+            field: Field,
+            setterCandidates: List<PojoMethod>,
+            constructor: Constructor?) {
         if (constructor != null && constructor.hasField(field)) {
             field.setter = FieldSetter(field.name, field.type, CallType.CONSTRUCTOR)
             return
@@ -625,7 +647,7 @@
                 candidates = setterCandidates,
                 nameVariations = field.setterNameWithVariations,
                 getType = { method ->
-                    method.parameters.first().asType()
+                    method.resolvedType.parameterTypes.first()
                 },
                 assignFromField = {
                     field.setter = FieldSetter(
@@ -634,9 +656,9 @@
                             callType = CallType.FIELD)
                 },
                 assignFromMethod = { match ->
-                    val paramType = match.parameters.first().asType()
+                    val paramType = match.resolvedType.parameterTypes.first()
                     field.setter = FieldSetter(
-                            name = match.simpleName.toString(),
+                            name = match.name,
                             type = paramType,
                             callType = CallType.METHOD)
                 },
@@ -653,12 +675,15 @@
      * At worst case, it sets to the field as if it is accessible so that the rest of the
      * compilation can continue.
      */
-    private fun chooseAssignment(field: Field, candidates: List<ExecutableElement>,
-                                 nameVariations: List<String>,
-                                 getType: (ExecutableElement) -> TypeMirror,
-                                 assignFromField: () -> Unit,
-                                 assignFromMethod: (ExecutableElement) -> Unit,
-                                 reportAmbiguity: (List<String>) -> Unit): Boolean {
+    private fun chooseAssignment(
+            field: Field,
+            candidates: List<PojoMethod>,
+            nameVariations: List<String>,
+            getType: (PojoMethod) -> TypeMirror,
+            assignFromField: () -> Unit,
+            assignFromMethod: (PojoMethod) -> Unit,
+            reportAmbiguity: (List<String>) -> Unit
+    ): Boolean {
         if (field.element.hasAnyOf(PUBLIC)) {
             assignFromField()
             return true
@@ -668,12 +693,12 @@
         val matching = candidates
                 .filter {
                     // b/69164099
-                    types.isAssignableWithoutVariance(getType(it), field.element.asType())
-                            && (field.nameWithVariations.contains(it.simpleName.toString())
-                            || nameVariations.contains(it.simpleName.toString()))
+                    types.isAssignableWithoutVariance(getType(it), field.type)
+                            && (field.nameWithVariations.contains(it.name)
+                            || nameVariations.contains(it.name))
                 }
                 .groupBy {
-                    if (it.hasAnyOf(PUBLIC)) PUBLIC else PROTECTED
+                    if (it.element.hasAnyOf(PUBLIC)) PUBLIC else PROTECTED
                 }
         if (matching.isEmpty()) {
             // we always assign to avoid NPEs in the rest of the compilation.
@@ -682,8 +707,8 @@
             // if not, compiler will tell, we didn't have any better alternative anyways.
             return !field.element.hasAnyOf(PRIVATE)
         }
-        val match = verifyAndChooseOneFrom(matching[PUBLIC], reportAmbiguity) ?:
-                verifyAndChooseOneFrom(matching[PROTECTED], reportAmbiguity)
+        val match = verifyAndChooseOneFrom(matching[PUBLIC], reportAmbiguity)
+                ?: verifyAndChooseOneFrom(matching[PROTECTED], reportAmbiguity)
         if (match == null) {
             assignFromField()
             return false
@@ -694,14 +719,14 @@
     }
 
     private fun verifyAndChooseOneFrom(
-            candidates: List<ExecutableElement>?,
+            candidates: List<PojoMethod>?,
             reportAmbiguity: (List<String>) -> Unit
-    ): ExecutableElement? {
+    ): PojoMethod? {
         if (candidates == null) {
             return null
         }
         if (candidates.size > 1) {
-            reportAmbiguity(candidates.map { it.simpleName.toString() })
+            reportAmbiguity(candidates.map { it.name })
         }
         return candidates.first()
     }
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/ProcessorErrors.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/ProcessorErrors.kt
index 7087059..02e299b 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/ProcessorErrors.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/ProcessorErrors.kt
@@ -448,6 +448,10 @@
                 to add $entity to the entities section of the @Database?
                 """.trim()
     }
+
+    val MISSING_ROOM_GUAVA_ARTIFACT = "To use Guava features, you must add `guava`" +
+            " artifact from Room as a dependency. android.arch.persistence.room:guava:<version>"
+
     val MISSING_ROOM_RXJAVA2_ARTIFACT = "To use RxJava2 features, you must add `rxjava2`" +
             " artifact from Room as a dependency. android.arch.persistence.room:rxjava2:<version>"
 
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/TransactionMethodProcessor.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/TransactionMethodProcessor.kt
index dbe6c6f..d35509d 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/TransactionMethodProcessor.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/TransactionMethodProcessor.kt
@@ -16,6 +16,7 @@
 
 package android.arch.persistence.room.processor
 
+import android.arch.persistence.room.ext.findKotlinDefaultImpl
 import android.arch.persistence.room.ext.hasAnyOf
 import android.arch.persistence.room.vo.TransactionMethod
 import javax.lang.model.element.ExecutableElement
@@ -32,13 +33,20 @@
     val context = baseContext.fork(executableElement)
 
     fun process(): TransactionMethod {
-        context.checker.check(!executableElement.hasAnyOf(PRIVATE, FINAL, ABSTRACT),
+        val kotlinDefaultImpl =
+                executableElement.findKotlinDefaultImpl(context.processingEnv.typeUtils)
+        context.checker.check(
+                !executableElement.hasAnyOf(PRIVATE, FINAL)
+                        && (!executableElement.hasAnyOf(ABSTRACT) || kotlinDefaultImpl != null),
                 executableElement, ProcessorErrors.TRANSACTION_METHOD_MODIFIERS)
 
-        val callType = if (executableElement.hasAnyOf(DEFAULT)) {
-            TransactionMethod.CallType.DEFAULT_IN_INTERFACE
-        } else {
-            TransactionMethod.CallType.CONCRETE
+        val callType = when {
+            executableElement.hasAnyOf(DEFAULT) ->
+                TransactionMethod.CallType.DEFAULT_JAVA8
+            kotlinDefaultImpl != null ->
+                TransactionMethod.CallType.DEFAULT_KOTLIN
+            else ->
+                TransactionMethod.CallType.CONCRETE
         }
 
         return TransactionMethod(
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/TypeAdapterStore.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/TypeAdapterStore.kt
index 13359f7..fc5c4d4 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/TypeAdapterStore.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/TypeAdapterStore.kt
@@ -28,11 +28,12 @@
 import android.arch.persistence.room.processor.FieldProcessor
 import android.arch.persistence.room.processor.PojoProcessor
 import android.arch.persistence.room.solver.binderprovider.CursorQueryResultBinderProvider
+import android.arch.persistence.room.solver.binderprovider.DataSourceFactoryQueryResultBinderProvider
 import android.arch.persistence.room.solver.binderprovider.DataSourceQueryResultBinderProvider
 import android.arch.persistence.room.solver.binderprovider.FlowableQueryResultBinderProvider
 import android.arch.persistence.room.solver.binderprovider.InstantQueryResultBinderProvider
 import android.arch.persistence.room.solver.binderprovider.LiveDataQueryResultBinderProvider
-import android.arch.persistence.room.solver.binderprovider.DataSourceFactoryQueryResultBinderProvider
+import android.arch.persistence.room.solver.binderprovider.GuavaListenableFutureQueryResultBinderProvider
 import android.arch.persistence.room.solver.binderprovider.RxMaybeQueryResultBinderProvider
 import android.arch.persistence.room.solver.binderprovider.RxSingleQueryResultBinderProvider
 import android.arch.persistence.room.solver.query.parameter.ArrayQueryParameterAdapter
@@ -137,6 +138,7 @@
             CursorQueryResultBinderProvider(context),
             LiveDataQueryResultBinderProvider(context),
             FlowableQueryResultBinderProvider(context),
+            GuavaListenableFutureQueryResultBinderProvider(context),
             RxMaybeQueryResultBinderProvider(context),
             RxSingleQueryResultBinderProvider(context),
             DataSourceQueryResultBinderProvider(context),
@@ -286,7 +288,7 @@
                 // The Optional adapter will reappend the Optional type.
                 val typeArg = declared.typeArguments.first()
                 val rowAdapter = findRowAdapter(typeArg, query) ?: return null
-                return GuavaOptionalQueryResultAdapter(rowAdapter)
+                return GuavaOptionalQueryResultAdapter(SingleEntityQueryResultAdapter(rowAdapter))
             } else if (
                     context.processingEnv.typeUtils.erasure(typeMirror).typeName() ==
                     CommonTypeNames.OPTIONAL) {
@@ -481,6 +483,11 @@
         }
     }
 
+    /**
+     * Returns all type converters that can receive input type and return into another type.
+     * The returned list is ordered by priority such that if we have an exact match, it is
+     * prioritized.
+     */
     private fun getAllTypeConverters(input: TypeMirror, excludes: List<TypeMirror>):
             List<TypeConverter> {
         val types = context.processingEnv.typeUtils
@@ -489,6 +496,13 @@
         return typeConverters.filter { converter ->
             types.isAssignable(input, converter.from) &&
                     !excludes.any { types.isSameType(it, converter.to) }
-        }
+        }.sortedByDescending {
+                    // if it is the same, prioritize
+                    if (types.isSameType(it.from, input)) {
+                        2
+                    } else {
+                        1
+                    }
+                }
     }
 }
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/binderprovider/GuavaListenableFutureQueryResultBinderProvider.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/binderprovider/GuavaListenableFutureQueryResultBinderProvider.kt
new file mode 100644
index 0000000..7876a63
--- /dev/null
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/binderprovider/GuavaListenableFutureQueryResultBinderProvider.kt
@@ -0,0 +1,64 @@
+/*
+ * 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.arch.persistence.room.solver.binderprovider
+
+import android.arch.persistence.room.ext.GuavaUtilConcurrentTypeNames
+import android.arch.persistence.room.ext.RoomGuavaTypeNames
+import android.arch.persistence.room.ext.typeName
+import android.arch.persistence.room.parser.ParsedQuery
+import android.arch.persistence.room.processor.Context
+import android.arch.persistence.room.processor.ProcessorErrors
+import android.arch.persistence.room.solver.QueryResultBinderProvider
+import android.arch.persistence.room.solver.query.result.QueryResultBinder
+import android.arch.persistence.room.solver.query.result.GuavaListenableFutureQueryResultBinder
+import javax.lang.model.type.DeclaredType
+
+class GuavaListenableFutureQueryResultBinderProvider(val context: Context)
+    : QueryResultBinderProvider {
+
+    private val hasGuavaRoom by lazy {
+        context.processingEnv.elementUtils
+                .getTypeElement(RoomGuavaTypeNames.GUAVA_ROOM.toString()) != null
+    }
+
+    /**
+     * Returns the {@link GuavaListenableFutureQueryResultBinder} instance for the input type, if
+     * possible.
+     *
+     * <p>Emits a compiler error if the Guava Room extension library is not linked.
+     */
+    override fun provide(declared: DeclaredType, query: ParsedQuery): QueryResultBinder {
+        if (!hasGuavaRoom) {
+            context.logger.e(ProcessorErrors.MISSING_ROOM_GUAVA_ARTIFACT)
+        }
+
+        // Use the type T inside ListenableFuture<T> as the type to adapt and to pass into
+        // the binder.
+        val adapter = context.typeAdapterStore.findQueryResultAdapter(
+                declared.typeArguments.first(), query)
+        return GuavaListenableFutureQueryResultBinder(
+                declared.typeArguments.first(), adapter)
+    }
+
+    /**
+     * Returns true iff the input {@code declared} type is ListenableFuture<T>.
+     */
+    override fun matches(declared: DeclaredType): Boolean =
+        declared.typeArguments.size == 1 &&
+                context.processingEnv.typeUtils.erasure(declared).typeName() ==
+                        GuavaUtilConcurrentTypeNames.LISTENABLE_FUTURE
+}
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/GuavaListenableFutureQueryResultBinder.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/GuavaListenableFutureQueryResultBinder.kt
new file mode 100644
index 0000000..de57d78
--- /dev/null
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/GuavaListenableFutureQueryResultBinder.kt
@@ -0,0 +1,119 @@
+/*
+ * 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.arch.persistence.room.solver.query.result
+
+import android.arch.persistence.room.ext.AndroidTypeNames
+import android.arch.persistence.room.ext.L
+import android.arch.persistence.room.ext.N
+import android.arch.persistence.room.ext.RoomGuavaTypeNames
+import android.arch.persistence.room.ext.T
+import android.arch.persistence.room.ext.typeName
+import android.arch.persistence.room.solver.CodeGenScope
+import android.arch.persistence.room.writer.DaoWriter
+import com.squareup.javapoet.FieldSpec
+import com.squareup.javapoet.MethodSpec
+import com.squareup.javapoet.ParameterizedTypeName
+import com.squareup.javapoet.TypeSpec
+import javax.lang.model.element.Modifier
+import javax.lang.model.type.TypeMirror
+
+/**
+ * A ResultBinder that emits a ListenableFuture<T> where T is the input {@code typeArg}.
+ *
+ * <p>The Future runs on the background thread Executor.
+ */
+class GuavaListenableFutureQueryResultBinder(
+        val typeArg: TypeMirror,
+        adapter: QueryResultAdapter?)
+    : BaseObservableQueryResultBinder(adapter) {
+
+    override fun convertAndReturn(
+            roomSQLiteQueryVar: String,
+            canReleaseQuery: Boolean,
+            dbField: FieldSpec,
+            inTransaction: Boolean,
+            scope: CodeGenScope) {
+        // Callable<T>
+        val callableImpl = createCallableOfT(
+                roomSQLiteQueryVar,
+                dbField,
+                inTransaction,
+                scope)
+
+        scope.builder().apply {
+            addStatement(
+                    "return $T.createListenableFuture($L, $L, $L)",
+                    RoomGuavaTypeNames.GUAVA_ROOM,
+                    callableImpl,
+                    roomSQLiteQueryVar,
+                    canReleaseQuery)
+        }
+    }
+
+    /**
+     * Returns an anonymous subclass of Callable<T> that executes the database transaction and
+     * constitutes the result T.
+     *
+     * <p>Note that this method does not release the query object.
+     */
+    private fun createCallableOfT(
+            roomSQLiteQueryVar: String,
+            dbField: FieldSpec,
+            inTransaction: Boolean,
+            scope: CodeGenScope): TypeSpec {
+        return TypeSpec.anonymousClassBuilder("").apply {
+            superclass(
+                    ParameterizedTypeName.get(java.util.concurrent.Callable::class.typeName(),
+                            typeArg.typeName()))
+            addMethod(
+                    MethodSpec.methodBuilder("call").apply {
+                        // public T call() throws Exception {}
+                        returns(typeArg.typeName())
+                        addAnnotation(Override::class.typeName())
+                        addModifiers(Modifier.PUBLIC)
+                        addException(Exception::class.typeName())
+
+                        // Body.
+                        val transactionWrapper = if (inTransaction) {
+                            transactionWrapper(dbField)
+                        } else {
+                            null
+                        }
+                        transactionWrapper?.beginTransactionWithControlFlow()
+                        apply {
+                            val outVar = scope.getTmpVar("_result")
+                            val cursorVar = scope.getTmpVar("_cursor")
+                            addStatement("final $T $L = $N.query($L)", AndroidTypeNames.CURSOR,
+                                    cursorVar,
+                                    DaoWriter.dbField, roomSQLiteQueryVar)
+                            beginControlFlow("try").apply {
+                                val adapterScope = scope.fork()
+                                adapter?.convert(outVar, cursorVar, adapterScope)
+                                addCode(adapterScope.builder().build())
+                                transactionWrapper?.commitTransaction()
+                                addStatement("return $L", outVar)
+                            }
+                            nextControlFlow("finally").apply {
+                                addStatement("$L.close()", cursorVar)
+                            }
+                            endControlFlow()
+                        }
+                        transactionWrapper?.endTransactionWithControlFlow()
+                    }.build())
+        }.build()
+    }
+}
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/GuavaOptionalQueryResultAdapter.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/GuavaOptionalQueryResultAdapter.kt
index a09a35f..33fb37b 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/GuavaOptionalQueryResultAdapter.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/GuavaOptionalQueryResultAdapter.kt
@@ -21,39 +21,27 @@
 import android.arch.persistence.room.ext.T
 import android.arch.persistence.room.ext.typeName
 import android.arch.persistence.room.solver.CodeGenScope
+import com.squareup.javapoet.ParameterizedTypeName
 
 /**
  * Wraps a row adapter when there is only 1 item in the result, and the result's outer type is
  * {@link com.google.common.base.Optional}.
  */
-class GuavaOptionalQueryResultAdapter(rowAdapter: RowAdapter)
-        : QueryResultAdapter(rowAdapter) {
-    val type = rowAdapter.out
-    override fun convert(outVarName: String, cursorVarName: String, scope: CodeGenScope) {
+class GuavaOptionalQueryResultAdapter(private val resultAdapter: SingleEntityQueryResultAdapter)
+    : QueryResultAdapter(resultAdapter.rowAdapter) {
+    val type = resultAdapter.rowAdapter?.out
+    override fun convert(
+            outVarName: String, cursorVarName: String, scope: CodeGenScope) {
         scope.builder().apply {
-            rowAdapter?.onCursorReady(cursorVarName, scope)
             val valueVarName = scope.getTmpVar("_value")
-            addStatement("final $T $L;", type.typeName(), valueVarName)
+            resultAdapter?.convert(valueVarName, cursorVarName, scope)
             addStatement(
-                    "final $T<$T> $L", GuavaBaseTypeNames.OPTIONAL, type.typeName(), outVarName)
-            beginControlFlow("if($L.moveToFirst())", cursorVarName).apply {
-                // _value = X;
-                rowAdapter?.convert(valueVarName, cursorVarName, scope)
-                // _outVar = Optional.of(_value);
-                addStatement(
-                        // _outVar = Optional.of(X);
-                        "$L = $T.of($L)",
-                        outVarName,
-                        GuavaBaseTypeNames.OPTIONAL,
-                        valueVarName)
-            }
-            nextControlFlow("else").apply {
-                // _outVar = Optional.absent();
-                // Ignore the default value of the type - absent is absent is absent.
-                addStatement("$L = $T.absent()", outVarName, GuavaBaseTypeNames.OPTIONAL)
-            }
-            endControlFlow()
-            rowAdapter?.onCursorFinished()?.invoke(scope)
+                    "final $T $L = $T.fromNullable($L)",
+                    ParameterizedTypeName.get(GuavaBaseTypeNames.OPTIONAL, type?.typeName()),
+                    outVarName,
+                    GuavaBaseTypeNames.OPTIONAL,
+                    valueVarName)
         }
     }
 }
+
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/OptionalQueryResultAdapter.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/OptionalQueryResultAdapter.kt
index 6f08622..a092eee 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/OptionalQueryResultAdapter.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/OptionalQueryResultAdapter.kt
@@ -39,7 +39,7 @@
             resultAdapter?.convert(valueVarName, cursorVarName, scope)
             addStatement(
                     "final $T $L = $T.ofNullable($L)",
-                    ParameterizedTypeName.get(CommonTypeNames.OPTIONAL, type?.typeName()) ,
+                    ParameterizedTypeName.get(CommonTypeNames.OPTIONAL, type?.typeName()),
                     outVarName,
                     CommonTypeNames.OPTIONAL,
                     valueVarName)
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Dao.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Dao.kt
index 9afa44c..774624c 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Dao.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Dao.kt
@@ -50,10 +50,16 @@
         if (suffix == null) {
             suffix = ""
         }
-        "${typeName.simpleName()}${suffix}_Impl"
+        val path = arrayListOf<String>()
+        var enclosing = element.enclosingElement
+        while (enclosing is TypeElement) {
+            path.add(ClassName.get(enclosing as TypeElement).simpleName())
+            enclosing = enclosing.enclosingElement
+        }
+        path.reversed().joinToString("_") + "${typeName.simpleName()}${suffix}_Impl"
     }
 
-    val implTypeName by lazy {
+    val implTypeName: ClassName by lazy {
         ClassName.get(typeName.packageName(), implClassName)
     }
 }
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/PojoMethod.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/PojoMethod.kt
new file mode 100644
index 0000000..2a59ef8
--- /dev/null
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/PojoMethod.kt
@@ -0,0 +1,28 @@
+/*
+ * 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.arch.persistence.room.vo
+
+import javax.lang.model.element.ExecutableElement
+import javax.lang.model.type.ExecutableType
+
+/**
+ * An executable element processed as member of a class (pojo or entity)
+ */
+class PojoMethod(
+        val element: ExecutableElement,
+        val resolvedType: ExecutableType,
+        val name: String)
\ No newline at end of file
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/TransactionMethod.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/TransactionMethod.kt
index 58fd11b..10e1889 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/TransactionMethod.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/TransactionMethod.kt
@@ -20,6 +20,6 @@
 
 class TransactionMethod(val element: ExecutableElement, val name: String, val callType: CallType) {
     enum class CallType {
-        CONCRETE, DEFAULT_IN_INTERFACE
+        CONCRETE, DEFAULT_JAVA8, DEFAULT_KOTLIN
     }
 }
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/DaoWriter.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/DaoWriter.kt
index 1a30d11..357d4f8 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/DaoWriter.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/DaoWriter.kt
@@ -40,6 +40,7 @@
 import com.squareup.javapoet.ParameterSpec
 import com.squareup.javapoet.TypeName
 import com.squareup.javapoet.TypeSpec
+import org.jetbrains.kotlin.load.java.JvmAbi
 import stripNonJava
 import javax.annotation.processing.ProcessingEnvironment
 import javax.lang.model.element.ElementKind
@@ -55,7 +56,7 @@
  */
 class DaoWriter(val dao: Dao, val processingEnv: ProcessingEnvironment)
     : ClassWriter(dao.typeName) {
-    val declaredDao = MoreTypes.asDeclared(dao.element.asType())
+    private val declaredDao = MoreTypes.asDeclared(dao.element.asType())
 
     companion object {
         // TODO nothing prevents this from conflicting, we should fix.
@@ -215,11 +216,17 @@
                     append("super.$N(")
                     params.add(element.simpleName)
                 }
-                TransactionMethod.CallType.DEFAULT_IN_INTERFACE -> {
+                TransactionMethod.CallType.DEFAULT_JAVA8 -> {
                     append("$N.super.$N(")
                     params.add(element.enclosingElement.simpleName)
                     params.add(element.simpleName)
                 }
+                TransactionMethod.CallType.DEFAULT_KOTLIN -> {
+                    append("$N.$N.$N(this, ")
+                    params.add(element.enclosingElement.simpleName)
+                    params.add(JvmAbi.DEFAULT_IMPLS_CLASS_NAME)
+                    params.add(element.simpleName)
+                }
             }
             var first = true
             element.parameters.forEach {
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/DatabaseWriter.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/DatabaseWriter.kt
index e96112d..18d87b3 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/DatabaseWriter.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/DatabaseWriter.kt
@@ -19,6 +19,7 @@
 import android.arch.persistence.room.ext.L
 import android.arch.persistence.room.ext.N
 import android.arch.persistence.room.ext.RoomTypeNames
+import android.arch.persistence.room.ext.S
 import android.arch.persistence.room.ext.SupportDbTypeNames
 import android.arch.persistence.room.ext.T
 import android.arch.persistence.room.solver.CodeGenScope
@@ -28,6 +29,7 @@
 import com.squareup.javapoet.FieldSpec
 import com.squareup.javapoet.MethodSpec
 import com.squareup.javapoet.ParameterSpec
+import com.squareup.javapoet.TypeName
 import com.squareup.javapoet.TypeSpec
 import stripNonJava
 import javax.lang.model.element.Modifier
@@ -47,11 +49,38 @@
             superclass(database.typeName)
             addMethod(createCreateOpenHelper())
             addMethod(createCreateInvalidationTracker())
+            addMethod(createClearAllTables())
         }
         addDaoImpls(builder)
         return builder
     }
 
+    private fun createClearAllTables(): MethodSpec {
+        val scope = CodeGenScope(this)
+        return MethodSpec.methodBuilder("clearAllTables").apply {
+            val dbVar = scope.getTmpVar("_db")
+            addStatement("final $T $L = super.getOpenHelper().getWritableDatabase()",
+                    SupportDbTypeNames.DB, dbVar)
+            addAnnotation(Override::class.java)
+            addModifiers(PUBLIC)
+            returns(TypeName.VOID)
+            beginControlFlow("try").apply {
+                addStatement("super.beginTransaction()")
+                if (database.enableForeignKeys) {
+                    addStatement("$L.execSQL($S)", dbVar, "PRAGMA defer_foreign_keys = TRUE")
+                }
+                database.entities.forEach {
+                    addStatement("$L.execSQL($S)", dbVar, "DELETE FROM `${it.tableName}`")
+                }
+                addStatement("super.setTransactionSuccessful()")
+            }
+            nextControlFlow("finally").apply {
+                addStatement("super.endTransaction()")
+            }
+            endControlFlow()
+        }.build()
+    }
+
     private fun createCreateInvalidationTracker(): MethodSpec {
         return MethodSpec.methodBuilder("createInvalidationTracker").apply {
             addAnnotation(Override::class.java)
diff --git a/room/compiler/src/test/data/databasewriter/output/ComplexDatabase.java b/room/compiler/src/test/data/databasewriter/output/ComplexDatabase.java
index 522cd2d..17592a6 100644
--- a/room/compiler/src/test/data/databasewriter/output/ComplexDatabase.java
+++ b/room/compiler/src/test/data/databasewriter/output/ComplexDatabase.java
@@ -92,6 +92,18 @@
     }
 
     @Override
+    public void clearAllTables() {
+        final SupportSQLiteDatabase _db = super.getOpenHelper().getWritableDatabase();
+        try {
+            super.beginTransaction();
+            _db.execSQL("DELETE FROM `User`");
+            super.setTransactionSuccessful();
+        } finally {
+            super.endTransaction();
+        }
+    }
+
+    @Override
     ComplexDao getComplexDao() {
         if (_complexDao != null) {
             return _complexDao;
diff --git a/room/compiler/src/test/kotlin/android/arch/persistence/room/parser/SqlParserTest.kt b/room/compiler/src/test/kotlin/android/arch/persistence/room/parser/SqlParserTest.kt
index a1d03b6..e6e8c3b 100644
--- a/room/compiler/src/test/kotlin/android/arch/persistence/room/parser/SqlParserTest.kt
+++ b/room/compiler/src/test/kotlin/android/arch/persistence/room/parser/SqlParserTest.kt
@@ -97,6 +97,8 @@
                 `is`(setOf(Table("users", "users"))))
         assertThat(SqlParser.parse("select * from \"users\"").tables,
                 `is`(setOf(Table("users", "users"))))
+        assertThat(SqlParser.parse("select * from 'users'").tables,
+                `is`(setOf(Table("users", "users"))))
     }
 
     @Test
diff --git a/room/compiler/src/test/kotlin/android/arch/persistence/room/solver/TypeAdapterStoreTest.kt b/room/compiler/src/test/kotlin/android/arch/persistence/room/solver/TypeAdapterStoreTest.kt
index 43c0aa4..7ad370e 100644
--- a/room/compiler/src/test/kotlin/android/arch/persistence/room/solver/TypeAdapterStoreTest.kt
+++ b/room/compiler/src/test/kotlin/android/arch/persistence/room/solver/TypeAdapterStoreTest.kt
@@ -27,13 +27,14 @@
 import android.arch.persistence.room.ext.RoomTypeNames.STRING_UTIL
 import android.arch.persistence.room.ext.RxJava2TypeNames
 import android.arch.persistence.room.ext.T
+import android.arch.persistence.room.ext.typeName
 import android.arch.persistence.room.parser.SQLTypeAffinity
 import android.arch.persistence.room.processor.Context
 import android.arch.persistence.room.processor.ProcessorErrors
+import android.arch.persistence.room.solver.binderprovider.DataSourceFactoryQueryResultBinderProvider
 import android.arch.persistence.room.solver.binderprovider.DataSourceQueryResultBinderProvider
 import android.arch.persistence.room.solver.binderprovider.FlowableQueryResultBinderProvider
 import android.arch.persistence.room.solver.binderprovider.LiveDataQueryResultBinderProvider
-import android.arch.persistence.room.solver.binderprovider.DataSourceFactoryQueryResultBinderProvider
 import android.arch.persistence.room.solver.types.CompositeAdapter
 import android.arch.persistence.room.solver.types.TypeConverter
 import android.arch.persistence.room.testing.TestInvocation
@@ -43,6 +44,7 @@
 import com.google.testing.compile.CompileTester
 import com.google.testing.compile.JavaFileObjects
 import com.google.testing.compile.JavaSourcesSubjectFactory
+import com.squareup.javapoet.TypeName
 import org.hamcrest.CoreMatchers.`is`
 import org.hamcrest.CoreMatchers.instanceOf
 import org.hamcrest.CoreMatchers.notNullValue
@@ -74,6 +76,26 @@
     }
 
     @Test
+    fun testJavaLangBoolean() {
+        singleRun { invocation ->
+            val store = TypeAdapterStore.create(Context(invocation.processingEnv))
+            val boolean = invocation
+                    .processingEnv
+                    .elementUtils
+                    .getTypeElement("java.lang.Boolean")
+                    .asType()
+            val adapter = store.findColumnTypeAdapter(boolean, null)
+            assertThat(adapter, notNullValue())
+            assertThat(adapter, instanceOf(CompositeAdapter::class.java))
+            val composite = adapter as CompositeAdapter
+            assertThat(composite.intoStatementConverter?.from?.typeName(),
+                    `is`(TypeName.BOOLEAN.box()))
+            assertThat(composite.columnTypeAdapter.out.typeName(),
+                    `is`(TypeName.INT.box()))
+        }.compilesWithoutError()
+    }
+
+    @Test
     fun testVia1TypeAdapter() {
         singleRun { invocation ->
             val store = TypeAdapterStore.create(Context(invocation.processingEnv))
diff --git a/room/guava/build.gradle b/room/guava/build.gradle
new file mode 100644
index 0000000..8660aae
--- /dev/null
+++ b/room/guava/build.gradle
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+import static android.support.dependencies.DependenciesKt.*
+import android.support.LibraryGroups
+import android.support.LibraryVersions
+import android.support.SupportLibraryExtension
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
+
+dependencies {
+    api(project(":room:common"))
+    api(project(":room:runtime"))
+    api(project(":arch:runtime"))
+    api(SUPPORT_ANNOTATIONS, libs.support_exclude_config)
+    api(GUAVA_ANDROID)
+}
+
+supportLibrary {
+    name = "Android Room Guava"
+    publish = true
+    mavenVersion = LibraryVersions.ROOM
+    mavenGroup = LibraryGroups.ROOM
+    inceptionYear = "2018"
+    description = "Android Room Guava"
+    url = SupportLibraryExtension.ARCHITECTURE_URL
+}
\ No newline at end of file
diff --git a/room/guava/src/main/AndroidManifest.xml b/room/guava/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..7c5004a
--- /dev/null
+++ b/room/guava/src/main/AndroidManifest.xml
@@ -0,0 +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.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="android.arch.persistence.room.guava">
+</manifest>
diff --git a/room/guava/src/main/java/android/arch/persistence/room/guava/GuavaRoom.java b/room/guava/src/main/java/android/arch/persistence/room/guava/GuavaRoom.java
new file mode 100644
index 0000000..1c9a488
--- /dev/null
+++ b/room/guava/src/main/java/android/arch/persistence/room/guava/GuavaRoom.java
@@ -0,0 +1,72 @@
+/*
+ * 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.arch.persistence.room.guava;
+
+import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
+
+import android.arch.core.executor.ArchTaskExecutor;
+import android.arch.persistence.room.RoomSQLiteQuery;
+import android.support.annotation.RestrictTo;
+
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListenableFutureTask;
+
+import java.util.concurrent.Callable;
+
+/**
+ * A class to hold static methods used by code generation in Room's Guava compatibility library.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+@SuppressWarnings("unused") // Used in GuavaListenableFutureQueryResultBinder code generation.
+public class GuavaRoom {
+
+    private GuavaRoom() {}
+
+    /**
+     * Returns a {@link ListenableFuture<T>} created by submitting the input {@code callable} to
+     * {@link ArchTaskExecutor}'s background-threaded Executor.
+     */
+    public static <T> ListenableFuture<T> createListenableFuture(
+            final Callable<T> callable,
+            final RoomSQLiteQuery query,
+            final boolean releaseQuery) {
+        ListenableFutureTask<T> listenableFutureTask = ListenableFutureTask.create(callable);
+        ArchTaskExecutor.getInstance().executeOnDiskIO(listenableFutureTask);
+
+        if (releaseQuery) {
+            Futures.addCallback(
+                    listenableFutureTask,
+                    new FutureCallback<T>() {
+                        @Override
+                        public void onSuccess(T t) {
+                            query.release();
+                        }
+
+                        @Override
+                        public void onFailure(Throwable throwable) {
+                            query.release();
+                        }
+                    },
+                    directExecutor());
+        }
+
+        return listenableFutureTask;
+    }
+}
diff --git a/room/integration-tests/kotlintestapp/build.gradle b/room/integration-tests/kotlintestapp/build.gradle
index 5717296..1dc0a79 100644
--- a/room/integration-tests/kotlintestapp/build.gradle
+++ b/room/integration-tests/kotlintestapp/build.gradle
@@ -13,7 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
+// TO debug processor, run:
+//./gradlew :r:in:k:clean :r:in:k:cC --no-daemon
+// -Dorg.gradle.debug=true
+// -Dkotlin.compiler.execution.strategy="in-process"
 import static android.support.dependencies.DependenciesKt.*
 
 plugins {
@@ -41,8 +44,7 @@
     implementation(project(":persistence:db-framework"))
     implementation(project(":room:runtime"))
     implementation(project(":arch:runtime"))
-
-    implementation(SUPPORT_APPCOMPAT, libs.support_exclude_config)
+    implementation(project(":lifecycle:extensions"))
     kaptAndroidTest project(":room:compiler")
 
     androidTestImplementation(TEST_RUNNER) {
@@ -57,6 +59,7 @@
     androidTestImplementation project(':lifecycle:extensions')
     androidTestImplementation project(':lifecycle:common')
     androidTestImplementation project(':lifecycle:runtime')
+    androidTestImplementation project(':room:guava')
     androidTestImplementation project(':room:testing')
     androidTestImplementation project(':room:rxjava2')
     androidTestImplementation project(':arch:core-testing')
@@ -72,4 +75,4 @@
 supportTestApp {
     // to assert that room generates somewhat OK code.
     enableErrorProne = true
-}
\ No newline at end of file
+}
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/dao/BooksDao.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/dao/BooksDao.kt
index d8cba31..a3f3934 100644
--- a/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/dao/BooksDao.kt
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/dao/BooksDao.kt
@@ -18,8 +18,10 @@
 
 import android.arch.lifecycle.LiveData
 import android.arch.persistence.room.Dao
+import android.arch.persistence.room.Delete
 import android.arch.persistence.room.Insert
 import android.arch.persistence.room.Query
+import android.arch.persistence.room.Transaction
 import android.arch.persistence.room.TypeConverters
 import android.arch.persistence.room.integration.kotlintestapp.vo.Author
 import android.arch.persistence.room.integration.kotlintestapp.vo.Book
@@ -30,6 +32,7 @@
 import android.arch.persistence.room.integration.kotlintestapp.vo.PublisherWithBookSales
 import android.arch.persistence.room.integration.kotlintestapp.vo.PublisherWithBooks
 import com.google.common.base.Optional
+import com.google.common.util.concurrent.ListenableFuture
 import io.reactivex.Flowable
 import io.reactivex.Maybe
 import io.reactivex.Single
@@ -40,6 +43,9 @@
     @Insert
     fun addPublishers(vararg publishers: Publisher)
 
+    @Delete
+    fun deletePublishers(vararg publishers: Publisher)
+
     @Insert
     fun addAuthors(vararg authors: Author)
 
@@ -70,12 +76,18 @@
     fun getBookJavaOptional(bookId: String): java.util.Optional<Book>
 
     @Query("SELECT * FROM book WHERE bookId = :bookId")
+    fun getBookListenableFuture(bookId: String): ListenableFuture<Book>
+
+    @Query("SELECT * FROM book WHERE bookId = :bookId")
     fun getBookOptional(bookId: String): Optional<Book>
 
     @Query("SELECT * FROM book WHERE bookId = :bookId")
     fun getBookOptionalFlowable(bookId: String): Flowable<Optional<Book>>
 
     @Query("SELECT * FROM book WHERE bookId = :bookId")
+    fun getBookOptionalListenableFuture(bookId: String): ListenableFuture<Optional<Book>>
+
+    @Query("SELECT * FROM book WHERE bookId = :bookId")
     fun getBookSingle(bookId: String): Single<Book>
 
     @Query("SELECT * FROM book WHERE bookId = :bookId")
@@ -93,6 +105,10 @@
             "ON book.bookPublisherId = publisher.publisherId ")
     fun getBooksWithPublisherFlowable(): Flowable<List<BookWithPublisher>>
 
+    @Query("SELECT * FROM book INNER JOIN publisher " +
+            "ON book.bookPublisherId = publisher.publisherId ")
+    fun getBooksWithPublisherListenableFuture(): ListenableFuture<List<BookWithPublisher>>
+
     @Query("SELECT * FROM publisher WHERE publisherId = :publisherId")
     fun getPublisherWithBooks(publisherId: String): PublisherWithBooks
 
@@ -111,4 +127,17 @@
     @Query("SELECT * FROM book WHERE languages & :langs != 0 ORDER BY bookId ASC")
     @TypeConverters(Lang::class)
     fun findByLanguages(langs: Set<Lang>): List<Book>
+
+    @Transaction
+    fun deleteAndAddPublisher(oldPublisher: Publisher, newPublisher: Publisher,
+            fail: Boolean = false) {
+        deletePublishers(oldPublisher)
+        if (fail) {
+            throw RuntimeException()
+        }
+        addPublishers(newPublisher)
+    }
+
+    @Query("SELECT * FROM Publisher")
+    fun getPublishers(): List<Publisher>
 }
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/test/BooksDaoTest.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/test/BooksDaoTest.kt
index 82a8ab5..5f355fd 100644
--- a/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/test/BooksDaoTest.kt
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/test/BooksDaoTest.kt
@@ -30,7 +30,9 @@
 import io.reactivex.subscribers.TestSubscriber
 import org.hamcrest.CoreMatchers
 import org.hamcrest.CoreMatchers.`is`
+import org.hamcrest.CoreMatchers.equalTo
 import org.hamcrest.CoreMatchers.instanceOf
+import org.hamcrest.CoreMatchers.notNullValue
 import org.hamcrest.MatcherAssert.assertThat
 import org.junit.Assert.assertNotNull
 import org.junit.Test
@@ -67,6 +69,17 @@
     }
 
     @Test
+    fun bookByIdListenableFuture() {
+        booksDao.addAuthors(TestUtil.AUTHOR_1)
+        booksDao.addPublishers(TestUtil.PUBLISHER)
+        booksDao.addBooks(TestUtil.BOOK_1)
+
+        assertThat(
+                booksDao.getBookListenableFuture(TestUtil.BOOK_1.bookId).get(),
+                `is`<Book>(TestUtil.BOOK_1))
+    }
+
+    @Test
     fun bookByIdOptional() {
         booksDao.addAuthors(TestUtil.AUTHOR_1)
         booksDao.addPublishers(TestUtil.PUBLISHER)
@@ -78,6 +91,24 @@
     }
 
     @Test
+    fun bookByIdOptionalListenableFuture() {
+        booksDao.addAuthors(TestUtil.AUTHOR_1)
+        booksDao.addPublishers(TestUtil.PUBLISHER)
+        booksDao.addBooks(TestUtil.BOOK_1)
+
+        assertThat(
+                booksDao.getBookOptionalListenableFuture(TestUtil.BOOK_1.bookId).get(),
+                `is`<Optional<Book>>(Optional.of(TestUtil.BOOK_1)))
+    }
+
+    @Test
+    fun bookByIdOptionalListenableFutureAbsent() {
+        assertThat(
+                booksDao.getBookOptionalListenableFuture(TestUtil.BOOK_1.bookId).get(),
+                `is`<Optional<Book>>(Optional.absent()))
+    }
+
+    @Test
     fun bookByIdOptionalAbsent() {
         assertThat(
                 booksDao.getBookOptional(TestUtil.BOOK_1.bookId),
@@ -128,6 +159,21 @@
     }
 
     @Test
+    fun bookWithPublisherListenableFuture() {
+        booksDao.addAuthors(TestUtil.AUTHOR_1)
+        booksDao.addPublishers(TestUtil.PUBLISHER)
+        booksDao.addBooks(TestUtil.BOOK_1)
+
+        val expected = BookWithPublisher(TestUtil.BOOK_1.bookId, TestUtil.BOOK_1.title,
+                TestUtil.PUBLISHER)
+        val expectedList = ArrayList<BookWithPublisher>()
+        expectedList.add(expected)
+
+        assertThat(database.booksDao().getBooksWithPublisherListenableFuture().get(),
+                `is`<List<BookWithPublisher>>(expectedList))
+    }
+
+    @Test
     fun updateBookWithNullTitle() {
         booksDao.addPublishers(TestUtil.PUBLISHER)
         booksDao.addBooks(TestUtil.BOOK_1)
@@ -240,4 +286,38 @@
 
         assertThat(author, CoreMatchers.`is`<Author>(TestUtil.AUTHOR_1))
     }
+
+    @Test
+    fun deleteAndAddPublisher() {
+        booksDao.addPublishers(TestUtil.PUBLISHER)
+        booksDao.getPublishers().run {
+            assertThat(this.size, `is`(1))
+            assertThat(this.first(), `is`(equalTo(TestUtil.PUBLISHER)))
+        }
+        booksDao.deleteAndAddPublisher(TestUtil.PUBLISHER, TestUtil.PUBLISHER2)
+        booksDao.getPublishers().run {
+            assertThat(this.size, `is`(1))
+            assertThat(this.first(), `is`(equalTo(TestUtil.PUBLISHER2)))
+        }
+    }
+
+    @Test
+    fun deleteAndAddPublisher_failure() {
+        booksDao.addPublishers(TestUtil.PUBLISHER)
+        booksDao.getPublishers().run {
+            assertThat(this.size, `is`(1))
+            assertThat(this.first(), `is`(equalTo(TestUtil.PUBLISHER)))
+        }
+        var throwable: Throwable? = null
+        try {
+            booksDao.deleteAndAddPublisher(TestUtil.PUBLISHER, TestUtil.PUBLISHER2, true)
+        } catch (e: RuntimeException) {
+            throwable = e
+        }
+        assertThat(throwable, `is`(notNullValue()))
+        booksDao.getPublishers().run {
+            assertThat(this.size, `is`(1))
+            assertThat(this.first(), `is`(equalTo(TestUtil.PUBLISHER)))
+        }
+    }
 }
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/test/ItemWithNullableConstructor.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/test/ItemWithNullableConstructor.kt
new file mode 100644
index 0000000..091beae
--- /dev/null
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/test/ItemWithNullableConstructor.kt
@@ -0,0 +1,81 @@
+/*
+ * 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.arch.persistence.room.integration.kotlintestapp.test
+
+import android.arch.persistence.room.Dao
+import android.arch.persistence.room.Database
+import android.arch.persistence.room.Entity
+import android.arch.persistence.room.Insert
+import android.arch.persistence.room.PrimaryKey
+import android.arch.persistence.room.Query
+import android.arch.persistence.room.Room
+import android.arch.persistence.room.RoomDatabase
+import android.arch.persistence.room.RoomWarnings
+import android.support.test.InstrumentationRegistry
+import android.support.test.runner.AndroidJUnit4
+import org.hamcrest.CoreMatchers.`is`
+import org.hamcrest.MatcherAssert.assertThat
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class ItemWithNullableConstructor {
+    lateinit var db: Db
+    @Before
+    fun initDb() {
+        db = Room.inMemoryDatabaseBuilder(InstrumentationRegistry.getTargetContext(),
+                Db::class.java).build()
+    }
+
+    @After
+    fun closeDb() {
+        db.close()
+    }
+
+    @Test
+    fun insertWithNull() {
+        db.dao.insert(TestItem(null, null))
+        assertThat(db.dao.get(), `is`(TestItem(1, null)))
+    }
+
+    @Entity
+    data class TestItem(
+            @PrimaryKey(autoGenerate = true)
+            val id: Long? = null,
+            val nullable: Boolean?
+    )
+
+    @Dao
+    interface TestDao {
+        @Insert
+        fun insert(testItem: TestItem)
+
+        @Query("SELECT * FROM TestItem LIMIT 1")
+        fun get(): TestItem?
+    }
+
+    @Database(
+            version = 1,
+            entities = [TestItem::class],
+            exportSchema = false
+    )
+    @SuppressWarnings(RoomWarnings.MISSING_SCHEMA_LOCATION)
+    abstract class Db : RoomDatabase() {
+        abstract val dao: TestDao
+    }
+}
\ No newline at end of file
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/vo/PublisherWithBookSales.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/vo/PublisherWithBookSales.kt
index 01e7b81..0087331 100644
--- a/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/vo/PublisherWithBookSales.kt
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/vo/PublisherWithBookSales.kt
@@ -19,12 +19,11 @@
 import android.arch.persistence.room.Embedded
 import android.arch.persistence.room.Relation
 
-class PublisherWithBookSales {
-    @Embedded
-    var publisher: Publisher? = null
-    @Relation(parentColumn = "publisherId", // publisher.publisherId
-            entityColumn = "bookPublisherId", // book.bookPublisherId
-            entity = Book::class,
-            projection = ["salesCnt"])
-    var sales: List<Int>? = emptyList()
-}
\ No newline at end of file
+data class PublisherWithBookSales @JvmOverloads constructor(
+        @Embedded
+        val publisher: Publisher,
+        @Relation(parentColumn = "publisherId", // publisher.publisherId
+                entityColumn = "bookPublisherId", // book.bookPublisherId
+                entity = Book::class,
+                projection = ["salesCnt"])
+        var sales: List<Int>? = emptyList())
\ No newline at end of file
diff --git a/room/integration-tests/testapp/build.gradle b/room/integration-tests/testapp/build.gradle
index 00712f8..45ec9c6 100644
--- a/room/integration-tests/testapp/build.gradle
+++ b/room/integration-tests/testapp/build.gradle
@@ -47,8 +47,8 @@
     implementation(project(":room:rxjava2"))
     implementation(project(":paging:runtime"))
 
-    implementation(SUPPORT_RECYCLERVIEW, libs.support_exclude_config)
-    implementation(SUPPORT_APPCOMPAT, libs.support_exclude_config)
+    implementation(SUPPORT_RECYCLERVIEW_27, libs.support_exclude_config)
+    implementation(SUPPORT_APPCOMPAT_27, libs.support_exclude_config)
     annotationProcessor project(":room:compiler")
     androidTestAnnotationProcessor project(":room:compiler")
 
@@ -75,4 +75,4 @@
 supportTestApp {
     // to assert that room generates somewhat OK code.
     enableErrorProne = true
-}
\ No newline at end of file
+}
diff --git a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/ClearAllTablesTest.java b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/ClearAllTablesTest.java
new file mode 100644
index 0000000..70b33c4
--- /dev/null
+++ b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/ClearAllTablesTest.java
@@ -0,0 +1,153 @@
+/*
+ * 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.arch.persistence.room.integration.testapp.test;
+
+import static org.hamcrest.CoreMatchers.hasItem;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.collection.IsCollectionWithSize.hasSize;
+import static org.junit.Assert.assertThat;
+
+import android.arch.persistence.room.Dao;
+import android.arch.persistence.room.Database;
+import android.arch.persistence.room.Entity;
+import android.arch.persistence.room.ForeignKey;
+import android.arch.persistence.room.Insert;
+import android.arch.persistence.room.InvalidationTracker;
+import android.arch.persistence.room.PrimaryKey;
+import android.arch.persistence.room.Query;
+import android.arch.persistence.room.Room;
+import android.arch.persistence.room.RoomDatabase;
+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 org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+
+@SuppressWarnings("WeakerAccess")
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ClearAllTablesTest {
+
+    @Database(version = 1, entities = {Parent.class, Child.class}, exportSchema = false)
+    public abstract static class ClearAllTablesDatabase extends RoomDatabase {
+        abstract ClearAllTablesDao dao();
+    }
+
+    @Entity
+    public static class Parent {
+        @PrimaryKey
+        public long id;
+        public String name;
+
+        public Parent(long id, String name) {
+            this.id = id;
+            this.name = name;
+        }
+    }
+
+    @Entity(foreignKeys = {
+            @ForeignKey(entity = Parent.class, parentColumns = "id", childColumns = "parentId")})
+    public static class Child {
+        @PrimaryKey
+        public long id;
+        public String name;
+        public long parentId;
+
+        public Child(long id, String name, long parentId) {
+            this.id = id;
+            this.name = name;
+            this.parentId = parentId;
+        }
+    }
+
+    @Dao
+    public interface ClearAllTablesDao {
+        @Insert
+        void insertParent(Parent parent);
+
+        @Insert
+        void insertChild(Child child);
+
+        @Query("SELECT COUNT(*) FROM Parent")
+        int countParent();
+
+        @Query("SELECT COUNT(*) FROM Child")
+        int countChild();
+    }
+
+    private ClearAllTablesDatabase mDatabase;
+    private ClearAllTablesDao mDao;
+
+    @Before
+    public void setUp() {
+        final Context context = InstrumentationRegistry.getTargetContext();
+        mDatabase = Room.inMemoryDatabaseBuilder(context, ClearAllTablesDatabase.class).build();
+        mDao = mDatabase.dao();
+    }
+
+    @After
+    public void closeDatabase() {
+        mDatabase.close();
+    }
+
+    @Test
+    public void simple() {
+        mDao.insertParent(new Parent(1, "A"));
+        assertThat(mDao.countParent(), is(1));
+        mDatabase.clearAllTables();
+        assertThat(mDao.countParent(), is(0));
+    }
+
+    @Test
+    public void foreignKey() {
+        mDao.insertParent(new Parent(1, "A"));
+        mDao.insertChild(new Child(1, "a", 1));
+        assertThat(mDao.countParent(), is(1));
+        assertThat(mDao.countChild(), is(1));
+        mDatabase.clearAllTables();
+        assertThat(mDao.countParent(), is(0));
+        assertThat(mDao.countChild(), is(0));
+    }
+
+    @Test
+    public void observer() throws InterruptedException {
+        mDao.insertParent(new Parent(1, "A"));
+        assertThat(mDao.countParent(), is(1));
+        final CountDownLatch latch = new CountDownLatch(1);
+        mDatabase.getInvalidationTracker().addObserver(new InvalidationTracker.Observer("Parent") {
+            @Override
+            public void onInvalidated(@NonNull Set<String> tables) {
+                assertThat(tables, hasSize(1));
+                assertThat(tables, hasItem("Parent"));
+                assertThat(mDao.countParent(), is(0));
+                latch.countDown();
+            }
+        });
+        mDatabase.clearAllTables();
+        assertThat(latch.await(3000, TimeUnit.MILLISECONDS), is(true));
+    }
+}
diff --git a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/DaoNameConflictTest.java b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/DaoNameConflictTest.java
new file mode 100644
index 0000000..1b8bff4
--- /dev/null
+++ b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/DaoNameConflictTest.java
@@ -0,0 +1,143 @@
+/*
+ * 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.arch.persistence.room.integration.testapp.test;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import android.arch.persistence.room.Dao;
+import android.arch.persistence.room.Database;
+import android.arch.persistence.room.Entity;
+import android.arch.persistence.room.Insert;
+import android.arch.persistence.room.PrimaryKey;
+import android.arch.persistence.room.Query;
+import android.arch.persistence.room.Room;
+import android.arch.persistence.room.RoomDatabase;
+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.Objects;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class DaoNameConflictTest {
+    private ConflictDatabase mDb;
+    @Before
+    public void init() {
+        mDb = Room.inMemoryDatabaseBuilder(
+                InstrumentationRegistry.getTargetContext(),
+                ConflictDatabase.class
+        ).build();
+    }
+
+    @After
+    public void close() {
+        mDb.close();
+    }
+
+    @Test
+    public void readFromItem1() {
+        Item1 item1 = new Item1(1, "a");
+        mDb.item1Dao().insert(item1);
+        Item2 item2 = new Item2(2, "b");
+        mDb.item2Dao().insert(item2);
+        assertThat(mDb.item1Dao().get(), is(item1));
+        assertThat(mDb.item2Dao().get(), is(item2));
+    }
+
+    @Entity
+    static class Item1 {
+        @PrimaryKey
+        public int id;
+        public String name;
+
+        Item1(int id, String name) {
+            this.id = id;
+            this.name = name;
+        }
+
+        @Dao
+        public interface Store {
+            @Query("SELECT * FROM Item1 LIMIT 1")
+            Item1 get();
+            @Insert
+            void insert(Item1... items);
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+            Item1 item1 = (Item1) o;
+            return id == item1.id
+                    && Objects.equals(name, item1.name);
+        }
+
+        @Override
+        public int hashCode() {
+
+            return Objects.hash(id, name);
+        }
+    }
+
+    @Entity
+    static class Item2 {
+        @PrimaryKey
+        public int id;
+        public String name;
+
+        Item2(int id, String name) {
+            this.id = id;
+            this.name = name;
+        }
+
+        @Dao
+        public interface Store {
+            @Query("SELECT * FROM Item2 LIMIT 1")
+            Item2 get();
+            @Insert
+            void insert(Item2... items);
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+            Item2 item2 = (Item2) o;
+            return id == item2.id
+                    && Objects.equals(name, item2.name);
+        }
+
+        @Override
+        public int hashCode() {
+
+            return Objects.hash(id, name);
+        }
+    }
+
+    @Database(version = 1, exportSchema = false, entities = {Item1.class, Item2.class})
+    public abstract static class ConflictDatabase extends RoomDatabase {
+        public abstract Item1.Store item1Dao();
+        public abstract Item2.Store item2Dao();
+    }
+}
diff --git a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/GenericEntityTest.java b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/GenericEntityTest.java
new file mode 100644
index 0000000..6db28d4
--- /dev/null
+++ b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/GenericEntityTest.java
@@ -0,0 +1,158 @@
+/*
+ * 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.arch.persistence.room.integration.testapp.test;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import android.arch.persistence.room.Dao;
+import android.arch.persistence.room.Database;
+import android.arch.persistence.room.Entity;
+import android.arch.persistence.room.Insert;
+import android.arch.persistence.room.PrimaryKey;
+import android.arch.persistence.room.Query;
+import android.arch.persistence.room.Room;
+import android.arch.persistence.room.RoomDatabase;
+import android.support.annotation.NonNull;
+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.Objects;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class GenericEntityTest {
+    private GenericDb mDb;
+    private GenericDao mDao;
+
+    @Before
+    public void init() {
+        mDb = Room.inMemoryDatabaseBuilder(
+                InstrumentationRegistry.getTargetContext(),
+                GenericDb.class
+        ).build();
+        mDao = mDb.getDao();
+    }
+
+    @After
+    public void close() {
+        mDb.close();
+    }
+
+    @Test
+    public void readWriteEntity() {
+        EntityItem item = new EntityItem("abc", "def");
+        mDao.insert(item);
+        EntityItem received = mDao.get("abc");
+        assertThat(received, is(item));
+    }
+
+    @Test
+    public void readPojo() {
+        EntityItem item = new EntityItem("abc", "def");
+        mDao.insert(item);
+        PojoItem received = mDao.getPojo("abc");
+        assertThat(received.id, is("abc"));
+    }
+
+    static class Item<P, F> {
+        @NonNull
+        @PrimaryKey
+        public final P id;
+        private F mField;
+
+        Item(@NonNull P id) {
+            this.id = id;
+        }
+
+        public F getField() {
+            return mField;
+        }
+
+        public void setField(F field) {
+            mField = field;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+            Item<?, ?> item = (Item<?, ?>) o;
+            return Objects.equals(id, item.id)
+                    && Objects.equals(mField, item.mField);
+        }
+
+        @Override
+        public int hashCode() {
+
+            return Objects.hash(id, mField);
+        }
+    }
+
+    static class PojoItem extends Item<String, Integer> {
+        PojoItem(String id) {
+            super(id);
+        }
+    }
+
+    @Entity
+    static class EntityItem extends Item<String, Integer> {
+        public final String name;
+
+        EntityItem(String id, String name) {
+            super(id);
+            this.name = name;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+            EntityItem item = (EntityItem) o;
+            return Objects.equals(name, item.name);
+        }
+
+        @Override
+        public int hashCode() {
+
+            return Objects.hash(name);
+        }
+    }
+
+    @Dao
+    public interface GenericDao {
+        @Insert
+        void insert(EntityItem... items);
+
+        @Query("SELECT * FROM EntityItem WHERE id = :id")
+        EntityItem get(String id);
+
+        @Query("SELECT * FROM EntityItem WHERE id = :id")
+        PojoItem getPojo(String id);
+    }
+
+    @Database(version = 1, entities = {EntityItem.class}, exportSchema = false)
+    public abstract static class GenericDb extends RoomDatabase {
+        abstract GenericDao getDao();
+    }
+}
diff --git a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/WriteAheadLoggingTest.java b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/WriteAheadLoggingTest.java
new file mode 100644
index 0000000..8d8e0e8
--- /dev/null
+++ b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/WriteAheadLoggingTest.java
@@ -0,0 +1,209 @@
+/*
+ * 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.arch.persistence.room.integration.testapp.test;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalToIgnoringCase;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+
+import android.arch.lifecycle.LiveData;
+import android.arch.lifecycle.Observer;
+import android.arch.persistence.db.SupportSQLiteDatabase;
+import android.arch.persistence.room.InvalidationTracker;
+import android.arch.persistence.room.Room;
+import android.arch.persistence.room.RoomDatabase;
+import android.arch.persistence.room.integration.testapp.TestDatabase;
+import android.arch.persistence.room.integration.testapp.dao.UserDao;
+import android.arch.persistence.room.integration.testapp.vo.User;
+import android.content.Context;
+import android.database.Cursor;
+import android.support.annotation.NonNull;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.filters.SdkSuppress;
+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.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+@SdkSuppress(minSdkVersion = 16)
+public class WriteAheadLoggingTest {
+
+    private static final String DATABASE_NAME = "wal.db";
+    private TestDatabase mDatabase;
+
+    @Before
+    public void openDatabase() {
+        Context context = InstrumentationRegistry.getTargetContext();
+        context.deleteDatabase(DATABASE_NAME);
+        mDatabase = Room.databaseBuilder(context, TestDatabase.class, DATABASE_NAME)
+                .setJournalMode(RoomDatabase.JournalMode.WRITE_AHEAD_LOGGING)
+                .build();
+    }
+
+    @After
+    public void closeDatabase() {
+        mDatabase.close();
+        Context context = InstrumentationRegistry.getTargetContext();
+        context.deleteDatabase(DATABASE_NAME);
+    }
+
+    @Test
+    public void checkJournalMode() {
+        Cursor c = null;
+        try {
+            SupportSQLiteDatabase db = mDatabase.getOpenHelper().getWritableDatabase();
+            c = db.query("PRAGMA journal_mode");
+            c.moveToFirst();
+            String journalMode = c.getString(0);
+            assertThat(journalMode, is(equalToIgnoringCase("wal")));
+        } finally {
+            if (c != null) {
+                c.close();
+            }
+        }
+    }
+
+    @Test
+    public void disableWal() {
+        Context context = InstrumentationRegistry.getTargetContext();
+        mDatabase.close();
+        mDatabase = Room.databaseBuilder(context, TestDatabase.class, DATABASE_NAME)
+                .setJournalMode(RoomDatabase.JournalMode.TRUNCATE)
+                .build();
+        Cursor c = null;
+        try {
+            SupportSQLiteDatabase db = mDatabase.getOpenHelper().getWritableDatabase();
+            c = db.query("PRAGMA journal_mode");
+            c.moveToFirst();
+            String journalMode = c.getString(0);
+            assertThat(journalMode, is(not(equalToIgnoringCase("wal"))));
+        } finally {
+            if (c != null) {
+                c.close();
+            }
+        }
+    }
+
+    @Test
+    public void observeLiveData() {
+        UserDao dao = mDatabase.getUserDao();
+        LiveData<User> user1 = dao.liveUserById(1);
+        Observer<User> observer = startObserver(user1);
+        dao.insert(TestUtil.createUser(1));
+        verify(observer, timeout(30000).atLeastOnce())
+                .onChanged(argThat(user -> user != null && user.getId() == 1));
+        stopObserver(user1, observer);
+    }
+
+    @Test
+    public void parallelWrites() throws InterruptedException, ExecutionException {
+        int numberOfThreads = 10;
+        ExecutorService executor = Executors.newFixedThreadPool(numberOfThreads);
+        ArrayList<Future<Boolean>> futures = new ArrayList<>();
+        for (int i = 0; i < numberOfThreads; i++) {
+            final int id = i + 1;
+            futures.add(i, executor.submit(() -> {
+                User user = TestUtil.createUser(id);
+                user.setName("user" + id);
+                mDatabase.getUserDao().insert(user);
+                return true;
+            }));
+        }
+        LiveData<List<User>> usersList = mDatabase.getUserDao().liveUsersListByName("user");
+        Observer<List<User>> observer = startObserver(usersList);
+        for (Future future : futures) {
+            assertThat(future.get(), is(true));
+        }
+        verify(observer, timeout(3000).atLeastOnce())
+                .onChanged(argThat(users -> users != null && users.size() == numberOfThreads));
+        stopObserver(usersList, observer);
+    }
+
+    @Test
+    public void readInBackground() throws InterruptedException, ExecutionException {
+        final UserDao dao = mDatabase.getUserDao();
+        final User user1 = TestUtil.createUser(1);
+        dao.insert(user1);
+        Future<Boolean> future;
+        try {
+            mDatabase.beginTransaction();
+            dao.delete(user1);
+            ExecutorService executor = Executors.newSingleThreadExecutor();
+            future = executor.submit(() -> {
+                assertThat(dao.load(1), is(equalTo(user1)));
+                return true;
+            });
+            future.get();
+            mDatabase.setTransactionSuccessful();
+        } finally {
+            mDatabase.endTransaction();
+        }
+        assertThat(dao.count(), is(0));
+    }
+
+    @Test
+    public void invalidation() throws InterruptedException {
+        final CountDownLatch latch = new CountDownLatch(1);
+        mDatabase.getInvalidationTracker().addObserver(new InvalidationTracker.Observer("User") {
+            @Override
+            public void onInvalidated(@NonNull Set<String> tables) {
+                latch.countDown();
+            }
+        });
+        mDatabase.getUserDao().insert(TestUtil.createUser(1));
+        latch.await(3000, TimeUnit.MILLISECONDS);
+        for (int i = 0; i < 10; i++) {
+            // This can (occasionally) detect if there is an recursive loop in InvalidationTracker
+            // invalidating itself by running its refresh query in a transaction.
+            assertThat(mDatabase.inTransaction(), is(false));
+        }
+    }
+
+    private static <T> Observer<T> startObserver(LiveData<T> liveData) {
+        @SuppressWarnings("unchecked")
+        Observer<T> observer = mock(Observer.class);
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(() ->
+                liveData.observeForever(observer));
+        return observer;
+    }
+
+    private static <T> void stopObserver(LiveData<T> liveData, Observer<T> observer) {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(() ->
+                liveData.removeObserver(observer));
+    }
+}
diff --git a/room/integration-tests/testapp/src/main/java/android/arch/persistence/room/integration/testapp/PagedListCustomerAdapter.java b/room/integration-tests/testapp/src/main/java/android/arch/persistence/room/integration/testapp/PagedListCustomerAdapter.java
index b5f635c..eacea99 100644
--- a/room/integration-tests/testapp/src/main/java/android/arch/persistence/room/integration/testapp/PagedListCustomerAdapter.java
+++ b/room/integration-tests/testapp/src/main/java/android/arch/persistence/room/integration/testapp/PagedListCustomerAdapter.java
@@ -27,7 +27,7 @@
 import android.widget.TextView;
 
 /**
- * Sample adapter which uses a PagedListAdapterHelper.
+ * Sample adapter which uses a AsyncPagedListDiffer.
  */
 class PagedListCustomerAdapter extends PagedListAdapter<Customer, RecyclerView.ViewHolder> {
     private RecyclerView mRecyclerView;
@@ -78,8 +78,8 @@
     }
 
     @Override
-    public void setList(PagedList<Customer> pagedList) {
-        super.setList(pagedList);
+    public void submitList(PagedList<Customer> pagedList) {
+        super.submitList(pagedList);
 
         if (pagedList != null) {
             final boolean firstSet = !mSetObserved;
diff --git a/room/integration-tests/testapp/src/main/java/android/arch/persistence/room/integration/testapp/RoomPagedListActivity.java b/room/integration-tests/testapp/src/main/java/android/arch/persistence/room/integration/testapp/RoomPagedListActivity.java
index 0c79aee..66620ef 100644
--- a/room/integration-tests/testapp/src/main/java/android/arch/persistence/room/integration/testapp/RoomPagedListActivity.java
+++ b/room/integration-tests/testapp/src/main/java/android/arch/persistence/room/integration/testapp/RoomPagedListActivity.java
@@ -17,17 +17,14 @@
 package android.arch.persistence.room.integration.testapp;
 
 import android.arch.lifecycle.LiveData;
-import android.arch.lifecycle.Observer;
 import android.arch.lifecycle.ViewModelProviders;
 import android.arch.paging.PagedList;
 import android.arch.persistence.room.integration.testapp.database.Customer;
 import android.arch.persistence.room.integration.testapp.database.LastNameAscCustomerDataSource;
 import android.os.Bundle;
-import android.support.annotation.Nullable;
 import android.support.v7.app.AppCompatActivity;
 import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
-import android.view.View;
 import android.widget.Button;
 
 /**
@@ -68,19 +65,9 @@
             }
             livePagedList = viewModel.getLivePagedList(position);
         }
-        livePagedList.observe(this, new Observer<PagedList<Customer>>() {
-            @Override
-            public void onChanged(@Nullable PagedList<Customer> items) {
-                mAdapter.setList(items);
-            }
-        });
+        livePagedList.observe(this, items -> mAdapter.submitList(items));
         final Button button = findViewById(R.id.addButton);
-        button.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                viewModel.insertCustomer();
-            }
-        });
+        button.setOnClickListener(v -> viewModel.insertCustomer());
     }
 
     @Override
diff --git a/room/integration-tests/testapp/src/main/java/android/arch/persistence/room/integration/testapp/database/Customer.java b/room/integration-tests/testapp/src/main/java/android/arch/persistence/room/integration/testapp/database/Customer.java
index 65e9828..54fa531 100644
--- a/room/integration-tests/testapp/src/main/java/android/arch/persistence/room/integration/testapp/database/Customer.java
+++ b/room/integration-tests/testapp/src/main/java/android/arch/persistence/room/integration/testapp/database/Customer.java
@@ -19,7 +19,7 @@
 import android.arch.persistence.room.Entity;
 import android.arch.persistence.room.PrimaryKey;
 import android.support.annotation.NonNull;
-import android.support.v7.recyclerview.extensions.DiffCallback;
+import android.support.v7.util.DiffUtil;
 
 /**
  * Sample entity
@@ -96,7 +96,8 @@
                 + '}';
     }
 
-    public static final DiffCallback<Customer> DIFF_CALLBACK = new DiffCallback<Customer>() {
+    public static final DiffUtil.ItemCallback<Customer> DIFF_CALLBACK =
+            new DiffUtil.ItemCallback<Customer>() {
         @Override
         public boolean areContentsTheSame(@NonNull Customer oldItem, @NonNull Customer newItem) {
             return oldItem.equals(newItem);
diff --git a/room/runtime/api/current.txt b/room/runtime/api/current.txt
index 29cfa85..17948ee 100644
--- a/room/runtime/api/current.txt
+++ b/room/runtime/api/current.txt
@@ -5,6 +5,7 @@
     field public final boolean allowMainThreadQueries;
     field public final java.util.List<android.arch.persistence.room.RoomDatabase.Callback> callbacks;
     field public final android.content.Context context;
+    field public final android.arch.persistence.room.RoomDatabase.JournalMode journalMode;
     field public final android.arch.persistence.room.RoomDatabase.MigrationContainer migrationContainer;
     field public final java.lang.String name;
     field public final boolean requireMigration;
@@ -33,6 +34,7 @@
   public abstract class RoomDatabase {
     ctor public RoomDatabase();
     method public void beginTransaction();
+    method public abstract void clearAllTables();
     method public void close();
     method public android.arch.persistence.db.SupportSQLiteStatement compileStatement(java.lang.String);
     method protected abstract android.arch.persistence.room.InvalidationTracker createInvalidationTracker();
@@ -61,6 +63,7 @@
     method public android.arch.persistence.room.RoomDatabase.Builder<T> fallbackToDestructiveMigration();
     method public android.arch.persistence.room.RoomDatabase.Builder<T> fallbackToDestructiveMigrationFrom(java.lang.Integer...);
     method public android.arch.persistence.room.RoomDatabase.Builder<T> openHelperFactory(android.arch.persistence.db.SupportSQLiteOpenHelper.Factory);
+    method public android.arch.persistence.room.RoomDatabase.Builder<T> setJournalMode(android.arch.persistence.room.RoomDatabase.JournalMode);
   }
 
   public static abstract class RoomDatabase.Callback {
@@ -69,6 +72,14 @@
     method public void onOpen(android.arch.persistence.db.SupportSQLiteDatabase);
   }
 
+  public static final class RoomDatabase.JournalMode extends java.lang.Enum {
+    method public static android.arch.persistence.room.RoomDatabase.JournalMode valueOf(java.lang.String);
+    method public static final android.arch.persistence.room.RoomDatabase.JournalMode[] values();
+    enum_constant public static final android.arch.persistence.room.RoomDatabase.JournalMode AUTOMATIC;
+    enum_constant public static final android.arch.persistence.room.RoomDatabase.JournalMode TRUNCATE;
+    enum_constant public static final android.arch.persistence.room.RoomDatabase.JournalMode WRITE_AHEAD_LOGGING;
+  }
+
   public static class RoomDatabase.MigrationContainer {
     ctor public RoomDatabase.MigrationContainer();
     method public void addMigrations(android.arch.persistence.room.migration.Migration...);
diff --git a/room/runtime/src/main/java/android/arch/persistence/room/DatabaseConfiguration.java b/room/runtime/src/main/java/android/arch/persistence/room/DatabaseConfiguration.java
index 42acc1d..d032bff 100644
--- a/room/runtime/src/main/java/android/arch/persistence/room/DatabaseConfiguration.java
+++ b/room/runtime/src/main/java/android/arch/persistence/room/DatabaseConfiguration.java
@@ -61,6 +61,11 @@
     public final boolean allowMainThreadQueries;
 
     /**
+     * The journal mode for this database.
+     */
+    public final RoomDatabase.JournalMode journalMode;
+
+    /**
      * If true, Room should crash if a migration is missing.
      */
     public final boolean requireMigration;
@@ -79,6 +84,7 @@
      * @param migrationContainer The migration container for migrations.
      * @param callbacks The list of callbacks for database events.
      * @param allowMainThreadQueries Whether to allow main thread reads/writes or not.
+     * @param journalMode The journal mode. This has to be either TRUNCATE or WRITE_AHEAD_LOGGING.
      * @param requireMigration True if Room should require a valid migration if version changes,
      *                        instead of recreating the tables.
      * @param migrationNotRequiredFrom The collection of schema versions from which migrations
@@ -92,6 +98,7 @@
             @NonNull RoomDatabase.MigrationContainer migrationContainer,
             @Nullable List<RoomDatabase.Callback> callbacks,
             boolean allowMainThreadQueries,
+            RoomDatabase.JournalMode journalMode,
             boolean requireMigration,
             @Nullable Set<Integer> migrationNotRequiredFrom) {
         this.sqliteOpenHelperFactory = sqliteOpenHelperFactory;
@@ -100,6 +107,7 @@
         this.migrationContainer = migrationContainer;
         this.callbacks = callbacks;
         this.allowMainThreadQueries = allowMainThreadQueries;
+        this.journalMode = journalMode;
         this.requireMigration = requireMigration;
         this.mMigrationNotRequiredFrom = migrationNotRequiredFrom;
     }
diff --git a/room/runtime/src/main/java/android/arch/persistence/room/InvalidationTracker.java b/room/runtime/src/main/java/android/arch/persistence/room/InvalidationTracker.java
index b31dc13..86054ce 100644
--- a/room/runtime/src/main/java/android/arch/persistence/room/InvalidationTracker.java
+++ b/room/runtime/src/main/java/android/arch/persistence/room/InvalidationTracker.java
@@ -366,20 +366,19 @@
 
                 mCleanupStatement.executeUpdateDelete();
                 mQueryArgs[0] = mMaxVersion;
-                Cursor cursor = mDatabase.query(SELECT_UPDATED_TABLES_SQL, mQueryArgs);
-                //noinspection TryFinallyCanBeTryWithResources
-                try {
-                    while (cursor.moveToNext()) {
-                        final long version = cursor.getLong(0);
-                        final int tableId = cursor.getInt(1);
-
-                        mTableVersions[tableId] = version;
-                        hasUpdatedTable = true;
-                        // result is ordered so we can safely do this assignment
-                        mMaxVersion = version;
+                if (mDatabase.mWriteAheadLoggingEnabled) {
+                    // This transaction has to be on the underlying DB rather than the RoomDatabase
+                    // in order to avoid a recursive loop after endTransaction.
+                    SupportSQLiteDatabase db = mDatabase.getOpenHelper().getWritableDatabase();
+                    try {
+                        db.beginTransaction();
+                        hasUpdatedTable = checkUpdatedTable();
+                        db.setTransactionSuccessful();
+                    } finally {
+                        db.endTransaction();
                     }
-                } finally {
-                    cursor.close();
+                } else {
+                    hasUpdatedTable = checkUpdatedTable();
                 }
             } catch (IllegalStateException | SQLiteException exception) {
                 // may happen if db is closed. just log.
@@ -396,6 +395,26 @@
                 }
             }
         }
+
+        private boolean checkUpdatedTable() {
+            boolean hasUpdatedTable = false;
+            Cursor cursor = mDatabase.query(SELECT_UPDATED_TABLES_SQL, mQueryArgs);
+            //noinspection TryFinallyCanBeTryWithResources
+            try {
+                while (cursor.moveToNext()) {
+                    final long version = cursor.getLong(0);
+                    final int tableId = cursor.getInt(1);
+
+                    mTableVersions[tableId] = version;
+                    hasUpdatedTable = true;
+                    // result is ordered so we can safely do this assignment
+                    mMaxVersion = version;
+                }
+            } finally {
+                cursor.close();
+            }
+            return hasUpdatedTable;
+        }
     };
 
     /**
diff --git a/room/runtime/src/main/java/android/arch/persistence/room/RoomDatabase.java b/room/runtime/src/main/java/android/arch/persistence/room/RoomDatabase.java
index db7af1d..b2a9f0e 100644
--- a/room/runtime/src/main/java/android/arch/persistence/room/RoomDatabase.java
+++ b/room/runtime/src/main/java/android/arch/persistence/room/RoomDatabase.java
@@ -16,6 +16,8 @@
 
 package android.arch.persistence.room;
 
+import android.annotation.SuppressLint;
+import android.app.ActivityManager;
 import android.arch.core.executor.ArchTaskExecutor;
 import android.arch.persistence.db.SimpleSQLiteQuery;
 import android.arch.persistence.db.SupportSQLiteDatabase;
@@ -26,10 +28,14 @@
 import android.arch.persistence.room.migration.Migration;
 import android.content.Context;
 import android.database.Cursor;
+import android.os.Build;
 import android.support.annotation.CallSuper;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
+import android.support.annotation.RequiresApi;
 import android.support.annotation.RestrictTo;
+import android.support.annotation.WorkerThread;
+import android.support.v4.app.ActivityManagerCompat;
 import android.support.v4.util.SparseArrayCompat;
 import android.util.Log;
 
@@ -66,6 +72,7 @@
     private SupportSQLiteOpenHelper mOpenHelper;
     private final InvalidationTracker mInvalidationTracker;
     private boolean mAllowMainThreadQueries;
+    boolean mWriteAheadLoggingEnabled;
 
     @Nullable
     protected List<Callback> mCallbacks;
@@ -101,8 +108,14 @@
     @CallSuper
     public void init(@NonNull DatabaseConfiguration configuration) {
         mOpenHelper = createOpenHelper(configuration);
+        boolean wal = false;
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+            wal = configuration.journalMode == JournalMode.WRITE_AHEAD_LOGGING;
+            mOpenHelper.setWriteAheadLoggingEnabled(wal);
+        }
         mCallbacks = configuration.callbacks;
         mAllowMainThreadQueries = configuration.allowMainThreadQueries;
+        mWriteAheadLoggingEnabled = wal;
     }
 
     /**
@@ -137,6 +150,15 @@
     protected abstract InvalidationTracker createInvalidationTracker();
 
     /**
+     * Deletes all rows from all the tables that are registered to this database as
+     * {@link Database#entities()}.
+     * <p>
+     * This does NOT reset the auto-increment value generated by {@link PrimaryKey#autoGenerate()}.
+     */
+    @WorkerThread
+    public abstract void clearAllTables();
+
+    /**
      * Returns true if database connection is open and initialized.
      *
      * @return true if the database connection is open, false otherwise.
@@ -319,6 +341,53 @@
     }
 
     /**
+     * Journal modes for SQLite database.
+     *
+     * @see RoomDatabase.Builder#setJournalMode(JournalMode)
+     */
+    public enum JournalMode {
+
+        /**
+         * Let Room choose the journal mode. This is the default value when no explicit value is
+         * specified.
+         * <p>
+         * The actual value will be {@link #TRUNCATE} when the device runs API Level lower than 16
+         * or it is a low-RAM device. Otherwise, {@link #WRITE_AHEAD_LOGGING} will be used.
+         */
+        AUTOMATIC,
+
+        /**
+         * Truncate journal mode.
+         */
+        TRUNCATE,
+
+        /**
+         * Write-Ahead Logging mode.
+         */
+        @RequiresApi(Build.VERSION_CODES.JELLY_BEAN)
+        WRITE_AHEAD_LOGGING;
+
+        /**
+         * Resolves {@link #AUTOMATIC} to either {@link #TRUNCATE} or
+         * {@link #WRITE_AHEAD_LOGGING}.
+         */
+        @SuppressLint("NewApi")
+        JournalMode resolve(Context context) {
+            if (this != AUTOMATIC) {
+                return this;
+            }
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+                ActivityManager manager = (ActivityManager)
+                        context.getSystemService(Context.ACTIVITY_SERVICE);
+                if (manager != null && !ActivityManagerCompat.isLowRamDevice(manager)) {
+                    return WRITE_AHEAD_LOGGING;
+                }
+            }
+            return TRUNCATE;
+        }
+    }
+
+    /**
      * Builder for RoomDatabase.
      *
      * @param <T> The type of the abstract database class.
@@ -331,6 +400,7 @@
 
         private SupportSQLiteOpenHelper.Factory mFactory;
         private boolean mAllowMainThreadQueries;
+        private JournalMode mJournalMode;
         private boolean mRequireMigration;
         /**
          * Migrations, mapped by from-to pairs.
@@ -348,6 +418,7 @@
             mContext = context;
             mDatabaseClass = klass;
             mName = name;
+            mJournalMode = JournalMode.AUTOMATIC;
             mRequireMigration = true;
             mMigrationContainer = new MigrationContainer();
         }
@@ -417,6 +488,27 @@
         }
 
         /**
+         * Sets the journal mode for this database.
+         *
+         * <p>
+         * This value is ignored if the builder is initialized with
+         * {@link Room#inMemoryDatabaseBuilder(Context, Class)}.
+         * <p>
+         * The journal mode should be consistent across multiple instances of
+         * {@link RoomDatabase} for a single SQLite database file.
+         * <p>
+         * The default value is {@link JournalMode#AUTOMATIC}.
+         *
+         * @param journalMode The journal mode.
+         * @return this
+         */
+        @NonNull
+        public Builder<T> setJournalMode(@NonNull JournalMode journalMode) {
+            mJournalMode = journalMode;
+            return this;
+        }
+
+        /**
          * Allows Room to destructively recreate database tables if {@link Migration}s that would
          * migrate old database schemas to the latest schema version are not found.
          * <p>
@@ -523,8 +615,9 @@
             }
             DatabaseConfiguration configuration =
                     new DatabaseConfiguration(mContext, mName, mFactory, mMigrationContainer,
-                            mCallbacks, mAllowMainThreadQueries, mRequireMigration,
-                            mMigrationsNotRequiredFrom);
+                            mCallbacks, mAllowMainThreadQueries,
+                            mJournalMode.resolve(mContext),
+                            mRequireMigration, mMigrationsNotRequiredFrom);
             T db = Room.getGeneratedImplementation(mDatabaseClass, DB_IMPL_SUFFIX);
             db.init(configuration);
             return db;
diff --git a/room/runtime/src/main/java/android/arch/persistence/room/RoomOpenHelper.java b/room/runtime/src/main/java/android/arch/persistence/room/RoomOpenHelper.java
index aad6895..e66534d 100644
--- a/room/runtime/src/main/java/android/arch/persistence/room/RoomOpenHelper.java
+++ b/room/runtime/src/main/java/android/arch/persistence/room/RoomOpenHelper.java
@@ -21,6 +21,7 @@
 import android.arch.persistence.db.SupportSQLiteOpenHelper;
 import android.arch.persistence.room.migration.Migration;
 import android.database.Cursor;
+import android.os.Build;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.annotation.RestrictTo;
@@ -107,14 +108,28 @@
     @Override
     public void onOpen(SupportSQLiteDatabase db) {
         super.onOpen(db);
-        checkIdentity(db);
+        checkIdentity(db, mConfiguration != null
+                && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN
+                && mConfiguration.journalMode == RoomDatabase.JournalMode.WRITE_AHEAD_LOGGING);
         mDelegate.onOpen(db);
         // there might be too many configurations etc, just clear it.
         mConfiguration = null;
     }
 
-    private void checkIdentity(SupportSQLiteDatabase db) {
-        createMasterTableIfNotExists(db);
+    private void checkIdentity(SupportSQLiteDatabase db, boolean useTransaction) {
+        if (useTransaction) {
+            // This transaction is necessary in WAL mode in order to make sure this query is
+            // executed in a read-write connection.
+            try {
+                db.beginTransaction();
+                createMasterTableIfNotExists(db);
+                db.setTransactionSuccessful();
+            } finally {
+                db.endTransaction();
+            }
+        } else {
+            createMasterTableIfNotExists(db);
+        }
         String identityHash = "";
         Cursor cursor = db.query(new SimpleSQLiteQuery(RoomMasterTable.READ_QUERY));
         //noinspection TryFinallyCanBeTryWithResources
diff --git a/room/runtime/src/test/java/android/arch/persistence/room/BuilderTest.java b/room/runtime/src/test/java/android/arch/persistence/room/BuilderTest.java
index 2c9b9e7..215bc30 100644
--- a/room/runtime/src/test/java/android/arch/persistence/room/BuilderTest.java
+++ b/room/runtime/src/test/java/android/arch/persistence/room/BuilderTest.java
@@ -231,6 +231,7 @@
         assertThat(config.context, is(context));
         assertThat(config.name, is(nullValue()));
         assertThat(config.allowMainThreadQueries, is(false));
+        assertThat(config.journalMode, is(RoomDatabase.JournalMode.TRUNCATE));
         assertThat(config.sqliteOpenHelperFactory,
                 instanceOf(FrameworkSQLiteOpenHelperFactory.class));
     }
@@ -246,6 +247,16 @@
     }
 
     @Test
+    public void createWriteAheadLogging() {
+        Context context = mock(Context.class);
+        TestDatabase db = Room.databaseBuilder(context, TestDatabase.class, "foo")
+                .setJournalMode(RoomDatabase.JournalMode.WRITE_AHEAD_LOGGING).build();
+        assertThat(db, instanceOf(BuilderTest_TestDatabase_Impl.class));
+        DatabaseConfiguration config = ((BuilderTest_TestDatabase_Impl) db).mConfig;
+        assertThat(config.journalMode, is(RoomDatabase.JournalMode.WRITE_AHEAD_LOGGING));
+    }
+
+    @Test
     public void createWithFactoryAndVersion() {
         Context context = mock(Context.class);
         SupportSQLiteOpenHelper.Factory factory = mock(SupportSQLiteOpenHelper.Factory.class);
diff --git a/room/runtime/src/test/java/android/arch/persistence/room/BuilderTest_TestDatabase_Impl.java b/room/runtime/src/test/java/android/arch/persistence/room/BuilderTest_TestDatabase_Impl.java
index d261454..8e310e2 100644
--- a/room/runtime/src/test/java/android/arch/persistence/room/BuilderTest_TestDatabase_Impl.java
+++ b/room/runtime/src/test/java/android/arch/persistence/room/BuilderTest_TestDatabase_Impl.java
@@ -35,4 +35,8 @@
     protected InvalidationTracker createInvalidationTracker() {
         return null;
     }
+
+    @Override
+    public void clearAllTables() {
+    }
 }
diff --git a/room/testing/src/main/java/android/arch/persistence/room/testing/MigrationTestHelper.java b/room/testing/src/main/java/android/arch/persistence/room/testing/MigrationTestHelper.java
index 013dd37..3d05f8d 100644
--- a/room/testing/src/main/java/android/arch/persistence/room/testing/MigrationTestHelper.java
+++ b/room/testing/src/main/java/android/arch/persistence/room/testing/MigrationTestHelper.java
@@ -143,7 +143,7 @@
         RoomDatabase.MigrationContainer container = new RoomDatabase.MigrationContainer();
         DatabaseConfiguration configuration = new DatabaseConfiguration(
                 mInstrumentation.getTargetContext(), name, mOpenFactory, container, null, true,
-                true, Collections.<Integer>emptySet());
+                RoomDatabase.JournalMode.TRUNCATE, true, Collections.<Integer>emptySet());
         RoomOpenHelper roomOpenHelper = new RoomOpenHelper(configuration,
                 new CreatingDelegate(schemaBundle.getDatabase()),
                 schemaBundle.getDatabase().getIdentityHash(),
@@ -189,7 +189,7 @@
         container.addMigrations(migrations);
         DatabaseConfiguration configuration = new DatabaseConfiguration(
                 mInstrumentation.getTargetContext(), name, mOpenFactory, container, null, true,
-                true, Collections.<Integer>emptySet());
+                RoomDatabase.JournalMode.TRUNCATE, true, Collections.<Integer>emptySet());
         RoomOpenHelper roomOpenHelper = new RoomOpenHelper(configuration,
                 new MigratingDelegate(schemaBundle.getDatabase(), validateDroppedTables),
                 // we pass the same hash twice since an old schema does not necessarily have
diff --git a/samples/SupportCarDemos/src/main/AndroidManifest.xml b/samples/SupportCarDemos/src/main/AndroidManifest.xml
index 2bd4f5c..f976df6 100644
--- a/samples/SupportCarDemos/src/main/AndroidManifest.xml
+++ b/samples/SupportCarDemos/src/main/AndroidManifest.xml
@@ -20,7 +20,7 @@
     <application android:label="@string/activity_sample_code"
             android:supportsRtl="true"
             android:icon="@drawable/app_sample_code"
-            android:theme="@style/CarTheme">
+            android:theme="@style/Theme.Car.Light.NoActionBar">
 
         <activity android:name=".SupportCarDemoActivity">
             <intent-filter>
diff --git a/samples/SupportCarDemos/src/main/res/layout/paged_list_item.xml b/samples/SupportCarDemos/src/main/res/layout/paged_list_item.xml
index 26f9c5a..5a3b273 100644
--- a/samples/SupportCarDemos/src/main/res/layout/paged_list_item.xml
+++ b/samples/SupportCarDemos/src/main/res/layout/paged_list_item.xml
@@ -26,5 +26,5 @@
         android:layout_height="wrap_content"
         android:singleLine="true"
         android:ellipsize="end"
-        android:textAppearance="@style/CarBody1"/>
-</androidx.car.widget.ColumnCardView>
\ No newline at end of file
+        android:textAppearance="@style/TextAppearance.Car.Body1"/>
+</androidx.car.widget.ColumnCardView>
diff --git a/samples/SupportCarDemos/src/main/res/values/styles.xml b/samples/SupportCarDemos/src/main/res/values/styles.xml
index 80074d8..e749206 100644
--- a/samples/SupportCarDemos/src/main/res/values/styles.xml
+++ b/samples/SupportCarDemos/src/main/res/values/styles.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
-    <style name="CarListSubtitle" parent="CarTitle">
+    <style name="CarListSubtitle" parent="TextAppearance.Car.Title">
         <item name="android:textColor">@color/car_highlight</item>
     </style>
-</resources>
\ No newline at end of file
+</resources>
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/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SampleSliceProvider.java b/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SampleSliceProvider.java
index 85af90f..d845b72 100644
--- 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
@@ -39,6 +39,7 @@
 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.
@@ -57,7 +58,7 @@
 
     public static final String[] URI_PATHS = {"message", "wifi", "note", "ride", "toggle",
             "toggle2", "contact", "gallery", "weather", "reservation", "loadlist", "loadlist2",
-            "loadgrid", "loadgrid2", "inputrange", "range"};
+            "loadgrid", "loadgrid2", "inputrange", "range", "contact2"};
 
     /**
      * @return Uri with the provided path
@@ -100,6 +101,8 @@
                 return createTwoCustomToggleSlices(sliceUri);
             case "/contact":
                 return createContact(sliceUri);
+            case "/contact2":
+                return createContact2(sliceUri);
             case "/gallery":
                 return createGallery(sliceUri);
             case "/weather":
@@ -123,27 +126,36 @@
     }
 
     private Slice createWeather(Uri sliceUri) {
-        return new GridBuilder(getContext(), 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))
+                        .addImage(Icon.createWithResource(getContext(), R.drawable.weather_1),
+                                GridBuilder.SMALL_IMAGE)
                         .addText("MON")
                         .addTitleText("69\u00B0"))
                 .addCell(cb -> cb
-                        .addLargeImage(Icon.createWithResource(getContext(), R.drawable.weather_2))
+                        .addImage(Icon.createWithResource(getContext(), R.drawable.weather_2),
+                                GridBuilder.SMALL_IMAGE)
                         .addText("TUE")
                         .addTitleText("71\u00B0"))
                 .addCell(cb -> cb
-                        .addLargeImage(Icon.createWithResource(getContext(), R.drawable.weather_3))
+                        .addImage(Icon.createWithResource(getContext(), R.drawable.weather_3),
+                                GridBuilder.SMALL_IMAGE)
                         .addText("WED")
                         .addTitleText("76\u00B0"))
                 .addCell(cb -> cb
-                        .addLargeImage(Icon.createWithResource(getContext(), R.drawable.weather_4))
+                        .addImage(Icon.createWithResource(getContext(), R.drawable.weather_4),
+                                GridBuilder.SMALL_IMAGE)
                         .addText("THU")
                         .addTitleText("72\u00B0"))
                 .addCell(cb -> cb
-                        .addLargeImage(Icon.createWithResource(getContext(), R.drawable.weather_1))
+                        .addImage(Icon.createWithResource(getContext(), R.drawable.weather_1),
+                                GridBuilder.SMALL_IMAGE)
                         .addText("FRI")
-                        .addTitleText("68\u00B0"))
+                        .addTitleText("68\u00B0")))
                 .build();
     }
 
@@ -152,20 +164,71 @@
                 .setColor(0xff4285F4)
                 .addRow(b -> b
                     .setTitle("Family trip to Hawaii")
-                    .setSubtitle("Sep 30, 2017 - Oct 2, 2017")
-                    .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_cast),
-                            getBroadcastIntent(ACTION_TOAST, "cast photo album"))
-                    .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_share),
-                            getBroadcastIntent(ACTION_TOAST, "share photo album")))
+                    .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)))
+                        .addImage(Icon.createWithResource(getContext(), R.drawable.slices_1),
+                            GridBuilder.LARGE_IMAGE))
                     .addCell(cb -> cb
-                        .addLargeImage(Icon.createWithResource(getContext(), R.drawable.slices_2)))
+                        .addImage(Icon.createWithResource(getContext(), R.drawable.slices_2),
+                                GridBuilder.LARGE_IMAGE))
                     .addCell(cb -> cb
-                        .addLargeImage(Icon.createWithResource(getContext(), R.drawable.slices_3)))
+                        .addImage(Icon.createWithResource(getContext(), R.drawable.slices_3),
+                                GridBuilder.LARGE_IMAGE))
                     .addCell(cb -> cb
-                        .addLargeImage(Icon.createWithResource(getContext(), R.drawable.slices_4))))
+                        .addImage(Icon.createWithResource(getContext(), R.drawable.slices_4),
+                                GridBuilder.LARGE_IMAGE))
+                    .addCell(cb -> cb
+                        .addImage(Icon.createWithResource(getContext(), R.drawable.slices_2),
+                                GridBuilder.LARGE_IMAGE))
+                    .addCell(cb -> cb
+                        .addImage(Icon.createWithResource(getContext(), R.drawable.slices_3),
+                                GridBuilder.LARGE_IMAGE))
+                    .addCell(cb -> cb
+                        .addImage(Icon.createWithResource(getContext(), R.drawable.slices_4),
+                                GridBuilder.LARGE_IMAGE)))
+                .build();
+    }
+
+
+    private Slice createContact2(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),
+                                        GridBuilder.ICON_IMAGE)
+                                .addText("Call")
+                                .setContentIntent(getBroadcastIntent(ACTION_TOAST, "call")))
+                        .addCell(new GridBuilder.CellBuilder(gb)
+                                .addImage(Icon.createWithResource(getContext(), R.drawable.ic_text),
+                                        GridBuilder.ICON_IMAGE)
+                                .addText("Text")
+                                .setContentIntent(getBroadcastIntent(ACTION_TOAST, "text")))
+                        .addCell(new GridBuilder.CellBuilder(gb)
+                                .addImage(Icon.createWithResource(getContext(),
+                                        R.drawable.ic_video), GridBuilder.ICON_IMAGE)
+                                .setContentIntent(getBroadcastIntent(ACTION_TOAST, "video"))
+                                .addText("Video"))
+                        .addCell(new GridBuilder.CellBuilder(gb)
+                                .addImage(Icon.createWithResource(getContext(),
+                                        R.drawable.ic_email), GridBuilder.ICON_IMAGE)
+                                .addText("Email")
+                                .setContentIntent(getBroadcastIntent(ACTION_TOAST, "email"))))
                 .build();
     }
 
@@ -174,12 +237,15 @@
         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)
-                        .setContentIntent(getBroadcastIntent(ACTION_TOAST, "See contact info")))
+                        .setPrimaryAction(primaryAction))
                 .addRow(b -> b
                         .setTitleItem(Icon.createWithResource(getContext(), R.drawable.ic_call))
                         .setTitle("314-259-2653")
@@ -189,23 +255,15 @@
                         .setTitleItem(Icon.createWithResource(getContext(), R.drawable.ic_text))
                         .setTitle("You: Coooooool see you then")
                         .addEndItem(System.currentTimeMillis() - 40 * DateUtils.MINUTE_IN_MILLIS))
-                .addGrid(b -> b
-                        .addCell(cb -> cb
-                            .addImage(Icon.createWithResource(getContext(), R.drawable.ic_call))
-                            .addText("Call")
-                            .setContentIntent(getBroadcastIntent(ACTION_TOAST, "call")))
-                        .addCell(cb -> cb
-                            .addImage(Icon.createWithResource(getContext(), R.drawable.ic_text))
-                            .addText("Text")
-                            .setContentIntent(getBroadcastIntent(ACTION_TOAST, "text")))
-                        .addCell(cb ->cb
-                            .addImage(Icon.createWithResource(getContext(), R.drawable.ic_video))
-                            .setContentIntent(getBroadcastIntent(ACTION_TOAST, "video"))
-                            .addText("Video"))
-                        .addCell(cb -> cb
-                            .addImage(Icon.createWithResource(getContext(), R.drawable.ic_email))
-                            .addText("Email")
-                            .setContentIntent(getBroadcastIntent(ACTION_TOAST, "email"))))
+                .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();
     }
 
@@ -232,32 +290,36 @@
         // TODO: Remote input.
         return new ListBuilder(getContext(), sliceUri)
                 .setColor(0xfff4b400)
-                .addRow(b -> b
-                    .setTitle("Create new note")
-                    .setSubtitle("with this note taking app")
-                    .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_create),
-                            getBroadcastIntent(ACTION_TOAST, "create note"))
-                    .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_voice),
-                            getBroadcastIntent(ACTION_TOAST, "voice note"))
-                    .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_camera),
-                            getIntent("android.media.action.IMAGE_CAPTURE")))
+                .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)
-                .addRow(b -> b
+                .setHeader(b -> b
                     .setTitle("Upcoming trip to Seattle")
-                    .setSubtitle("Feb 1 - 19 | 2 guests")
-                    .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_location),
-                            getBroadcastIntent(ACTION_TOAST, "show reservation location on map"))
-                    .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_text),
-                            getBroadcastIntent(ACTION_TOAST, "contact host")))
+                    .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))))
+                        .addImage(Icon.createWithResource(getContext(), R.drawable.reservation),
+                            GridBuilder.LARGE_IMAGE)))
                 .addGrid(b -> b
                     .addCell(cb -> cb
                         .addTitleText("Check In")
@@ -277,23 +339,27 @@
         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")
-                    .setContentIntent(getBroadcastIntent(ACTION_TOAST, "get ride")))
+                    .setPrimaryAction(primaryAction))
                 .addRow(b -> b
                     .setTitle("Work")
                     .setSubtitle(workSubtitle)
-                    .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_work),
-                            getBroadcastIntent(ACTION_TOAST, "work")))
+                    .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(Icon.createWithResource(getContext(), R.drawable.ic_home),
-                            getBroadcastIntent(ACTION_TOAST, "home")))
+                    .addEndItem(new SliceAction(getBroadcastIntent(ACTION_TOAST, "home"),
+                            Icon.createWithResource(getContext(), R.drawable.ic_home),
+                            "Get ride home")))
                 .build();
     }
 
@@ -303,9 +369,10 @@
                 .addRow(b -> b
                     .setTitle("Custom toggle")
                     .setSubtitle("It can support two states")
-                    .addToggle(getBroadcastIntent(ACTION_TOAST, "star toggled"),
-                            true /* isChecked */,
-                            Icon.createWithResource(getContext(), R.drawable.toggle_star)))
+                    .setPrimaryAction(new SliceAction(getBroadcastIntent(ACTION_TOAST,
+                            "star toggled"),
+                            Icon.createWithResource(getContext(), R.drawable.toggle_star),
+                            "Toggle star", true /* isChecked */)))
                 .build();
     }
 
@@ -315,12 +382,14 @@
                 .addRow(b -> b
                         .setTitle("2 toggles")
                         .setSubtitle("each supports two states")
-                        .addToggle(getBroadcastIntent(ACTION_TOAST, "first star toggled"),
-                                true /* isChecked */,
-                                Icon.createWithResource(getContext(), R.drawable.toggle_star))
-                        .addToggle(getBroadcastIntent(ACTION_TOAST, "second star toggled"),
-                                false /* isChecked */,
-                                Icon.createWithResource(getContext(), R.drawable.toggle_star)))
+                        .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();
     }
 
@@ -346,14 +415,16 @@
                 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")
-                    .setTitleItem(Icon.createWithResource(getContext(), R.drawable.ic_wifi))
                     .setSubtitle(state)
-                    .addToggle(getBroadcastIntent(ACTION_WIFI_CHANGED, null), finalWifiEnabled)
-                    .setContentIntent(getIntent(Settings.ACTION_WIFI_SETTINGS)))
+                    .addEndItem(new SliceAction(getBroadcastIntent(ACTION_WIFI_CHANGED, null),
+                            "Toggle wifi", finalWifiEnabled))
+                    .setPrimaryAction(primaryAction))
                 .build();
     }
 
@@ -397,9 +468,7 @@
                 mHandler.postDelayed(mLoader, LOADING_DELAY_MS);
             }
             if (loadAll) {
-                return isList
-                        ? new ListBuilder(getContext(), sliceUri).build()
-                        : new GridBuilder(getContext(), sliceUri).build();
+                return new ListBuilder(getContext(), sliceUri).build();
             }
             return createPartialSlice(sliceUri, true, isList);
         } else {
@@ -418,13 +487,17 @@
                         .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").addToggle(intent2, false, true))
+                        .addRow(b -> b
+                                .setTitle("My title")
+                                .addEndItem(new SliceAction(intent2, "Some action",
+                                        false /* isChecked */),
+                                        true /* isLoading */))
                         .build();
             } else {
-                return new GridBuilder(getContext(), sliceUri)
+                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))
+                        .addCell(b -> createCell(b, null, null, null, true)))
                         .build();
             }
         } else {
@@ -434,13 +507,16 @@
                                 "Subtitle loaded", icon, intent, false))
                         .addRow(b -> createRow(b, "Loaded row", "Loaded subtitle",
                                 icon, intent, false))
-                        .addRow(b -> b.setTitle("My title").addToggle(intent2, false))
+                        .addRow(b -> b
+                                .setTitle("My title")
+                                .addEndItem(new SliceAction(intent2, "Some action",
+                                                false /* isChecked */)))
                         .build();
             } else {
-                return new GridBuilder(getContext(), sliceUri)
+                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))
+                        .addCell(b -> createCell(b, "Three stars", "best", icon, false)))
                         .build();
             }
         }
@@ -448,15 +524,17 @@
 
     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)
-          .setContentIntent(content);
+          .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);
+        return cb.addText(text1, isLoading).addText(text2, isLoading).addImage(icon,
+                GridBuilder.SMALL_IMAGE, isLoading);
     }
 
     private PendingIntent getIntent(String action) {
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
index 7015743..d9d0284 100644
--- 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
@@ -221,14 +221,8 @@
     }
 
     private void addSlice(Intent intent) {
-        SliceView v = TEST_THEMES
-                ? (SliceView) getLayoutInflater().inflate(R.layout.slice_view, mContainer, false)
-                : new SliceView(getApplicationContext());
-        v.setOnSliceActionListener(this);
+        SliceView v = createSliceView();
         v.setTag(intent);
-        if (mSliceLiveData != null) {
-            mSliceLiveData.removeObservers(this);
-        }
         mContainer.removeAllViews();
         mContainer.addView(v);
         mSliceLiveData = SliceLiveData.fromIntent(this, intent);
@@ -238,15 +232,8 @@
 
     private void addSlice(Uri uri) {
         if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
-            SliceView v = TEST_THEMES
-                    ? (SliceView) getLayoutInflater().inflate(
-                            R.layout.slice_view, mContainer, false)
-                    : new SliceView(getApplicationContext());
-            v.setOnSliceActionListener(this);
+            SliceView v = createSliceView();
             v.setTag(uri);
-            if (mSliceLiveData != null) {
-                mSliceLiveData.removeObservers(this);
-            }
             mContainer.removeAllViews();
             mContainer.addView(v);
             mSliceLiveData = SliceLiveData.fromUri(this, uri);
@@ -292,4 +279,16 @@
         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/SupportTransitionDemos/proguard.flags b/samples/SupportTransitionDemos/proguard.flags
deleted file mode 100644
index e69de29..0000000
--- a/samples/SupportTransitionDemos/proguard.flags
+++ /dev/null
diff --git a/settings.gradle b/settings.gradle
index a5704cc..06b1c32 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -15,71 +15,84 @@
 //   the Maven artifactId
 //
 def includeProject(name, filePath) {
-  settings.include(name)
+    settings.include(name)
 
-  def file
-  if (filePath instanceof String) {
-    file = new File(filePath)
-  } else {
-    file = filePath
-  }
-  project(name).projectDir = file
+    def file
+    if (filePath instanceof String) {
+        file = new File(filePath)
+    } else {
+        file = filePath
+    }
+    project(name).projectDir = file
 }
 
 
-
-
 /////////////////////////////
 //
 // Libraries
 //
 /////////////////////////////
 
-includeProject(":support-annotations", "annotations")
-includeProject(":support-compat", "compat")
-includeProject(":support-media-compat", "media-compat")
-includeProject(":support-core-ui", "core-ui")
-includeProject(":support-fragment", "fragment")
-includeProject(":support-core-utils", "core-utils")
-includeProject(":support-v4", "v4")
-includeProject(":appcompat-v7", "v7/appcompat")
-includeProject(":gridlayout-v7", "v7/gridlayout")
-includeProject(":mediarouter-v7", "v7/mediarouter")
-includeProject(":palette-v7", "v7/palette")
-includeProject(":recyclerview-v7", "v7/recyclerview")
-includeProject(":recyclerview-selection", "recyclerview-selection")
-includeProject(":cardview-v7", "v7/cardview")
-includeProject(":preference-v7", "v7/preference")
-includeProject(":preference-v14", "v14/preference")
-includeProject(":preference-leanback-v17", "preference-leanback")
-includeProject(":support-v13", "v13")
-includeProject(":leanback-v17", "leanback")
-includeProject(":percent", "percent")
-includeProject(":customtabs", "customtabs")
-includeProject(":recommendation", "recommendation")
-includeProject(":support-vector-drawable", "graphics/drawable/static")
 includeProject(":animated-vector-drawable", "graphics/drawable/animated")
-includeProject(":transition", "transition")
-includeProject(":support-dynamic-animation", "dynamic-animation")
-includeProject(":viewpager2", "viewpager2")
-includeProject(":exifinterface", "exifinterface")
-includeProject(":wear", "wear")
-includeProject(":support-tv-provider", "tv-provider")
-includeProject(":support-emoji", "emoji/core")
-includeProject(":support-emoji-bundled", "emoji/bundled")
-includeProject(":support-emoji-appcompat", "emoji/appcompat")
-includeProject(":support-content", "content")
+includeProject(":appcompat-v7", "v7/appcompat")
+includeProject(":asynclayoutinflater", "asynclayoutinflater")
 includeProject(":car", "car")
-includeProject(":webkit", "webkit")
-includeProject(":slices-core", "slices/core")
-includeProject(":slices-view", "slices/view")
-includeProject(":slices-builders", "slices/builders")
-includeProject(":textclassifier", "textclassifier")
-includeProject(":webkit-codegen", "webkit-codegen")
+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")
 
 /////////////////////////////
 //
@@ -89,24 +102,24 @@
 
 File samplesRoot = new File(rootDir, "samples")
 
+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-vector-drawable-demos", new File(samplesRoot, "SupportVectorDrawableDemos"))
-includeProject(":support-animation-demos", new File(samplesRoot, "SupportAnimationDemos"))
-includeProject(":viewpager2-demos", new File(samplesRoot, "ViewPager2Demos"))
 includeProject(":support-wear-demos", new File(samplesRoot, "SupportWearDemos"))
-includeProject(":support-app-navigation", new File(samplesRoot, "SupportAppNavigation"))
-includeProject(":support-emoji-demos", new File(samplesRoot, "SupportEmojiDemos"))
-includeProject(":support-car-demos", new File(samplesRoot, "SupportCarDemos"))
-includeProject(":support-slices-demos", new File(samplesRoot, "SupportSliceDemos"))
+includeProject(":viewpager2-demos", new File(samplesRoot, "ViewPager2Demos"))
 
 /////////////////////////////
 //
@@ -138,6 +151,7 @@
 File externalRoot = new File(rootDir, "../../external")
 
 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/builders/api/current.txt b/slices/builders/api/current.txt
index 8a953cb..ccfc07f 100644
--- a/slices/builders/api/current.txt
+++ b/slices/builders/api/current.txt
@@ -1,22 +1,27 @@
 package androidx.app.slice.builders {
 
   public class GridBuilder extends androidx.app.slice.builders.TemplateSliceBuilder {
-    ctor public GridBuilder(android.content.Context, android.net.Uri);
     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);
+    field public static final int ICON_IMAGE = 0; // 0x0
+    field public static final int LARGE_IMAGE = 2; // 0x2
+    field public static final int SMALL_IMAGE = 1; // 0x1
   }
 
   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 deprecated androidx.app.slice.builders.GridBuilder.CellBuilder addImage(android.graphics.drawable.Icon);
+    method public deprecated androidx.app.slice.builders.GridBuilder.CellBuilder addImage(android.graphics.drawable.Icon, boolean);
+    method public androidx.app.slice.builders.GridBuilder.CellBuilder addImage(android.graphics.drawable.Icon, int);
+    method public androidx.app.slice.builders.GridBuilder.CellBuilder addImage(android.graphics.drawable.Icon, int, boolean);
+    method public deprecated androidx.app.slice.builders.GridBuilder.CellBuilder addLargeImage(android.graphics.drawable.Icon);
+    method public deprecated 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);
@@ -26,6 +31,7 @@
 
   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);
@@ -37,21 +43,13 @@
     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 setActions(androidx.app.slice.builders.ListBuilder.ActionBuilder);
-    method public androidx.app.slice.builders.ListBuilder setActions(java.util.function.Consumer<androidx.app.slice.builders.ListBuilder.ActionBuilder>);
     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.ActionBuilder extends androidx.app.slice.builders.TemplateSliceBuilder {
-    ctor public ListBuilder.ActionBuilder(androidx.app.slice.builders.ListBuilder);
-    method public androidx.app.slice.builders.ListBuilder.ActionBuilder addAction(android.app.PendingIntent, android.graphics.drawable.Icon, java.lang.CharSequence, int);
-    method public androidx.app.slice.builders.ListBuilder.ActionBuilder addAction(android.app.PendingIntent, android.graphics.drawable.Icon, java.lang.CharSequence);
-  }
-
   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 setContentIntent(android.app.PendingIntent);
+    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);
@@ -80,13 +78,9 @@
     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(android.graphics.drawable.Icon, android.app.PendingIntent);
-    method public androidx.app.slice.builders.ListBuilder.RowBuilder addEndItem(android.graphics.drawable.Icon, android.app.PendingIntent, boolean);
-    method public androidx.app.slice.builders.ListBuilder.RowBuilder addToggle(android.app.PendingIntent, boolean);
-    method public androidx.app.slice.builders.ListBuilder.RowBuilder addToggle(android.app.PendingIntent, boolean, boolean);
-    method public androidx.app.slice.builders.ListBuilder.RowBuilder addToggle(android.app.PendingIntent, boolean, android.graphics.drawable.Icon);
-    method public androidx.app.slice.builders.ListBuilder.RowBuilder addToggle(android.app.PendingIntent, boolean, android.graphics.drawable.Icon, boolean);
-    method public androidx.app.slice.builders.ListBuilder.RowBuilder setContentIntent(android.app.PendingIntent);
+    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);
@@ -94,8 +88,24 @@
     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(android.graphics.drawable.Icon, android.app.PendingIntent);
-    method public androidx.app.slice.builders.ListBuilder.RowBuilder setTitleItem(android.graphics.drawable.Icon, android.app.PendingIntent, 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 {
diff --git a/slices/builders/build.gradle b/slices/builders/build.gradle
index ae7407b..491617a 100644
--- a/slices/builders/build.gradle
+++ b/slices/builders/build.gradle
@@ -31,7 +31,7 @@
     name = "Slice builders"
     publish = true
     mavenVersion = LibraryVersions.SUPPORT_LIBRARY
-    mavenGroup = LibraryGroups.SLICES
+    mavenGroup = LibraryGroups.SUPPORT
     inceptionYear = "2017"
     description = "A set of builders to create templates using SliceProvider APIs"
     minSdkVersion = 24
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
index 0dff405..8d34f57 100644
--- a/slices/builders/src/main/java/androidx/app/slice/builders/GridBuilder.java
+++ b/slices/builders/src/main/java/androidx/app/slice/builders/GridBuilder.java
@@ -19,10 +19,10 @@
 import static android.support.annotation.RestrictTo.Scope.LIBRARY;
 
 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.IntDef;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.annotation.RequiresApi;
@@ -30,10 +30,6 @@
 
 import java.util.function.Consumer;
 
-import androidx.app.slice.Slice;
-import androidx.app.slice.SliceSpecs;
-import androidx.app.slice.builders.impl.GridBuilderBasicImpl;
-import androidx.app.slice.builders.impl.GridBuilderListV1Impl;
 import androidx.app.slice.builders.impl.TemplateBuilderImpl;
 
 
@@ -50,12 +46,26 @@
     private boolean mHasSeeMore;
 
     /**
-     * Create a builder which will construct a slice displayed in a grid format.
-     * @param uri Uri to tag for this slice.
+     * @hide
      */
-    public GridBuilder(@NonNull Context context, @NonNull Uri uri) {
-        super(new Slice.Builder(uri), context);
-    }
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    @IntDef({
+            LARGE_IMAGE, SMALL_IMAGE, ICON_IMAGE
+    })
+    public @interface ImageMode{}
+
+    /**
+     * Indicates that an image presented in the grid is a icon and it can be tinted.
+     */
+    public static final int ICON_IMAGE = 0;
+    /**
+     * Indicates that an image presented in the grid should be displayed in a small format.
+     */
+    public static final int SMALL_IMAGE = 1;
+    /**
+     * Indicates that an image presented in the grid should be displayed in a large format.
+     */
+    public static final int LARGE_IMAGE = 2;
 
     /**
      * Create a builder which will construct a slice displayed in a grid format.
@@ -66,26 +76,6 @@
     }
 
     @Override
-    @NonNull
-    public Slice build() {
-        return mImpl.buildIndividual();
-    }
-
-    /**
-     * @hide
-     */
-    @RestrictTo(LIBRARY)
-    @Override
-    protected TemplateBuilderImpl selectImpl() {
-        if (checkCompatible(SliceSpecs.GRID)) {
-            return new GridBuilderListV1Impl(getBuilder(), SliceSpecs.GRID);
-        } else if (checkCompatible(SliceSpecs.BASIC)) {
-            return new GridBuilderBasicImpl(getBuilder(), SliceSpecs.GRID);
-        }
-        return null;
-    }
-
-    @Override
     void setImpl(TemplateBuilderImpl impl) {
         mImpl = (androidx.app.slice.builders.impl.GridBuilder) impl;
     }
@@ -179,6 +169,14 @@
         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
@@ -288,8 +286,9 @@
          * @param image the image to display in the cell.
          */
         @NonNull
+        @Deprecated
         public CellBuilder addLargeImage(@NonNull Icon image) {
-            return addLargeImage(image, false /* isLoading */);
+            return addImage(image, LARGE_IMAGE, false /* isLoading */);
         }
 
         /**
@@ -303,9 +302,9 @@
          *                  background or not.
          */
         @NonNull
+        @Deprecated
         public CellBuilder addLargeImage(@Nullable Icon image, boolean isLoading) {
-            mImpl.addLargeImage(image, isLoading);
-            return this;
+            return addImage(image, LARGE_IMAGE, isLoading);
         }
 
         /**
@@ -315,8 +314,9 @@
          * @param image the image to display in the cell.
          */
         @NonNull
+        @Deprecated
         public CellBuilder addImage(@NonNull Icon image) {
-            return addImage(image, false /* isLoading */);
+            return addImage(image, SMALL_IMAGE, false /* isLoading */);
         }
 
         /**
@@ -330,8 +330,47 @@
          *                  background or not.
          */
         @NonNull
+        @Deprecated
         public CellBuilder addImage(@Nullable Icon image, boolean isLoading) {
-            mImpl.addImage(image, isLoading);
+            return addImage(image, SMALL_IMAGE, 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.
+         * @param imageMode the mode that image should be displayed in.
+         *
+         * @see #ICON_IMAGE
+         * @see #SMALL_IMAGE
+         * @see #LARGE_IMAGE
+         */
+        @NonNull
+        public CellBuilder addImage(@NonNull Icon image, @ImageMode int imageMode) {
+            return addImage(image, imageMode, 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 image the image to display in the cell.
+         * @param imageMode the mode that image should be displayed in.
+         * @param isLoading indicates whether the app is doing work to load the added content in the
+         *                  background or not.
+         *
+         * @see #ICON_IMAGE
+         * @see #SMALL_IMAGE
+         * @see #LARGE_IMAGE
+         */
+        @NonNull
+        public CellBuilder addImage(@Nullable Icon image, @ImageMode int imageMode,
+                boolean isLoading) {
+            mImpl.addImage(image, imageMode, isLoading);
             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
index dbd3a98..fd7ac96 100644
--- a/slices/builders/src/main/java/androidx/app/slice/builders/ListBuilder.java
+++ b/slices/builders/src/main/java/androidx/app/slice/builders/ListBuilder.java
@@ -24,6 +24,7 @@
 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;
@@ -140,42 +141,27 @@
     }
 
     /**
-     * Sets the group of actions for this template. These actions may be shown on the template in
-     * large or small formats. Generally these actions will be displayed in the order they were
-     * added to the {@link ActionBuilder}, however, if not all actions can be displayed then
+     * 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 ActionBuilder#addAction(PendingIntent, Icon, CharSequence, int)
+     * @see SliceAction
+     * @see SliceAction#setPriority(int)
      */
     @NonNull
-    public ListBuilder setActions(@NonNull ActionBuilder builder) {
-        mImpl.setActions((TemplateBuilderImpl) builder.mImpl);
+    public ListBuilder addAction(@NonNull SliceAction action) {
+        mImpl.addAction(action);
         return this;
     }
 
     /**
-     * Sets the group of actions for this template. These actions may be shown on the template in
-     * large or small formats. Generally these actions will be displayed in the order they were
-     * added to the {@link ActionBuilder}, however, if not all actions can be displayed then
-     * actions with a higher priority may be shown first.
-     *
-     * @see ActionBuilder#addAction(PendingIntent, Icon, CharSequence, int)
-     */
-    @RequiresApi(api = Build.VERSION_CODES.N)
-    @NonNull
-    public ListBuilder setActions(@NonNull Consumer<ActionBuilder> c) {
-        ActionBuilder b = new ActionBuilder(this);
-        c.accept(b);
-        return setActions(b);
-    }
-
-    /**
      * Sets the color to tint items displayed by this template (e.g. icons).
      * @hide
      */
     @RestrictTo(LIBRARY_GROUP)
     @NonNull
-    public ListBuilder setColor(int color) {
+    public ListBuilder setColor(@ColorInt int color) {
         mImpl.setColor(color);
         return this;
     }
@@ -515,8 +501,8 @@
          * replace any other title items that may have been set.
          */
         @NonNull
-        public RowBuilder setTitleItem(@NonNull Icon icon, @NonNull PendingIntent action) {
-            return setTitleItem(icon, action, false /* isLoading */);
+        public RowBuilder setTitleItem(@NonNull SliceAction action) {
+            return setTitleItem(action, false /* isLoading */);
         }
 
         /**
@@ -530,9 +516,8 @@
          *                  background or not.
          */
         @NonNull
-        public RowBuilder setTitleItem(@NonNull Icon icon, @NonNull PendingIntent action,
-                boolean isLoading) {
-            mImpl.setTitleItem(icon, action, isLoading);
+        public RowBuilder setTitleItem(@NonNull SliceAction action, boolean isLoading) {
+            mImpl.setTitleItem(action, isLoading);
             return this;
         }
 
@@ -540,8 +525,8 @@
          * Sets the action to be invoked if the user taps on the main content of the template.
          */
         @NonNull
-        public RowBuilder setContentIntent(@NonNull PendingIntent action) {
-            mImpl.setContentIntent(action);
+        public RowBuilder setPrimaryAction(@NonNull SliceAction action) {
+            mImpl.setPrimaryAction(action);
             return this;
         }
 
@@ -608,8 +593,8 @@
         }
 
         /**
-         * Adds an icon to be displayed at the end of the row. A mixture of icons and tappable
-         * icons is not permitted. If an action has already been added this will throw
+         * 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
@@ -618,8 +603,8 @@
         }
 
         /**
-         * Adds an icon to be displayed at the end of the row. A mixture of icons and tappable
-         * icons is not permitted. If an action has already been added this will throw
+         * 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
@@ -633,7 +618,7 @@
             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 "
-                        + "tappable icons and icons.");
+                        + "actions and icons.");
             }
             mImpl.addEndItem(icon, isLoading);
             mHasEndImage = true;
@@ -641,18 +626,18 @@
         }
 
         /**
-         * Adds a tappable icon to be displayed at the end of the row. A mixture of icons and
-         * tappable icons is not permitted. If an icon has already been added, this will throw
+         * 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 Icon icon, @NonNull PendingIntent action) {
-            return addEndItem(icon, action, false /* isLoading */);
+        public RowBuilder addEndItem(@NonNull SliceAction action) {
+            return addEndItem(action, false /* isLoading */);
         }
 
         /**
-         * Adds a tappable icon to be displayed at the end of the row. A mixture of icons and
-         * tappable icons is not permitted. If an icon has already been added, this will throw
+         * 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
@@ -662,83 +647,19 @@
          *                  background or not.
          */
         @NonNull
-        public RowBuilder addEndItem(@Nullable Icon icon, @Nullable PendingIntent action,
-                boolean isLoading) {
-            mImpl.addEndItem(icon, action, isLoading);
-            return this;
-        }
-
-        /**
-         * Adds a toggle action to be displayed at the end of the row. A mixture of icons and
-         * tappable icons is not permitted. If an icon has already been added, this will throw an
-         * {@link IllegalArgumentException}.
-         */
-        @NonNull
-        public RowBuilder addToggle(@NonNull PendingIntent action, boolean isChecked) {
-            return addToggle(action, isChecked, null, false /* isLoading */);
-        }
-
-        /**
-         * Adds a toggle action to be displayed at the end of the row. A mixture of icons and
-         * tappable icons is not permitted. If an icon has already been added, this will throw an
-         * {@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 addToggle(@NonNull PendingIntent action, boolean isChecked,
-                boolean isLoading) {
-            return addToggleInternal(action, isChecked, null, isLoading);
-        }
-
-        /**
-         * Adds a toggle action to be displayed with custom icons to represent checked and
-         * unchecked state at the end of the row. A mixture of icons and tappable icons is not
-         * permitted. If an icon has already been added, this will throw an
-         * {@link IllegalArgumentException}.
-         */
-        @NonNull
-        public RowBuilder addToggle(@NonNull PendingIntent action, boolean isChecked,
-                @NonNull Icon icon) {
-            return addToggle(action, isChecked, icon, false /* isLoading */);
-        }
-
-        /**
-         * Adds a toggle action to be displayed with custom icons to represent checked and
-         * unchecked state at the end of the row. A mixture of icons and tappable icons is not
-         * permitted. If an icon has already been added, this will throw an
-         * {@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 addToggle(@NonNull PendingIntent action, boolean isChecked,
-                @NonNull Icon icon, boolean isLoading) {
-            return addToggleInternal(action, isChecked, icon, isLoading);
-        }
-
-        private RowBuilder addToggleInternal(@NonNull PendingIntent action, boolean isChecked,
-                @Nullable Icon icon, boolean isLoading) {
+        public RowBuilder addEndItem(@NonNull SliceAction action, boolean isLoading) {
             if (mHasEndImage) {
-                throw new IllegalStateException("Trying to add a toggle to end items when an "
+                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 "
-                        + "tappable icons and icons.");
+                        + "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.addToggle(action, isChecked, icon, isLoading);
-            mHasDefaultToggle = icon == null;
+            mImpl.addEndItem(action, isLoading);
+            mHasDefaultToggle = action.isDefaultToggle();
             mHasEndActionOrToggle = true;
             return this;
         }
@@ -747,6 +668,15 @@
         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;
+        }
+
     }
 
     /**
@@ -804,11 +734,11 @@
         }
 
         /**
-         * Sets the pending intent to activate when the header is activated.
+         * Sets the action to invoke when the header is activated.
          */
         @NonNull
-        public HeaderBuilder setContentIntent(@NonNull PendingIntent intent) {
-            mImpl.setContentIntent(intent);
+        public HeaderBuilder setPrimaryAction(@NonNull SliceAction action) {
+            mImpl.setPrimaryAction(action);
             return this;
         }
 
@@ -817,63 +747,4 @@
             mImpl = (androidx.app.slice.builders.impl.ListBuilder.HeaderBuilder) impl;
         }
     }
-
-    /**
-     * Builder to construct a group of actions.
-     *
-     * @see ListBuilder#setActions(ActionBuilder)
-     */
-    public static class ActionBuilder extends TemplateSliceBuilder  {
-        private androidx.app.slice.builders.impl.ListBuilder.ActionBuilder mImpl;
-
-        /**
-         * Create a builder to construct a group of actions
-         */
-        public ActionBuilder(@NonNull ListBuilder parent) {
-            super(parent.mImpl.createActionBuilder());
-        }
-
-        /**
-         * Create a builder to construct a group of actions
-         * @hide
-         */
-        @RestrictTo(LIBRARY_GROUP)
-        public ActionBuilder(@NonNull ListBuilder parent, @NonNull Uri uri) {
-            super(parent.mImpl.createHeaderBuilder(uri));
-        }
-
-        /**
-         * Adds an action to this builder.
-         *
-         * @param action the pending intent to send when the action is activated.
-         * @param actionIcon the icon to display for this action.
-         * @param contentDescription the content description to use for accessibility.
-         * @param priority what priority to display this action in, with the lowest priority having
-         *                 the highest ranking.
-         */
-        @NonNull
-        public ActionBuilder addAction(@NonNull PendingIntent action, @NonNull Icon actionIcon,
-                @NonNull CharSequence contentDescription, int priority) {
-            mImpl.addAction(action, actionIcon, contentDescription, priority);
-            return this;
-        }
-
-        /**
-         * Adds an action to this builder.
-         *
-         * @param action the pending intent to send when the action is activated.
-         * @param actionIcon the icon to display for this action.
-         * @param contentDescription the content description to use for accessibility.
-         */
-        @NonNull
-        public ActionBuilder addAction(@NonNull PendingIntent action, @NonNull Icon actionIcon,
-                @NonNull CharSequence contentDescription) {
-            return addAction(action, actionIcon, contentDescription, -1);
-        }
-
-        @Override
-        void setImpl(TemplateBuilderImpl impl) {
-            mImpl = (androidx.app.slice.builders.impl.ListBuilder.ActionBuilder) 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/impl/GridBuilder.java b/slices/builders/src/main/java/androidx/app/slice/builders/impl/GridBuilder.java
index 302e1b3..dfca415 100644
--- 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
@@ -25,7 +25,7 @@
 import android.support.annotation.Nullable;
 import android.support.annotation.RestrictTo;
 
-import androidx.app.slice.Slice;
+import androidx.app.slice.builders.SliceAction;
 
 /**
  * @hide
@@ -70,9 +70,9 @@
     void addSeeMoreAction(PendingIntent intent);
 
     /**
-     * Builds a standalone slice of this grid builder (i.e. not contained within a List).
+     * Sets the action to be invoked if the user taps on the main content of the template.
      */
-    Slice buildIndividual();
+    void setPrimaryAction(SliceAction action);
 
     /**
      */
@@ -116,33 +116,14 @@
         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.
+         * @param imageMode the mode that image should be displayed in.
          */
         @NonNull
-        void addImage(@NonNull Icon image);
+        void addImage(@NonNull Icon image, int imageMode);
 
         /**
          * Adds an image to the cell. There can be at most one image, the first one added
@@ -153,7 +134,7 @@
          * until updated.l.
          */
         @NonNull
-        void addImage(@NonNull Icon image, boolean isLoading);
+        void addImage(@NonNull Icon image, int imageMode, boolean isLoading);
 
         /**
          * Sets the action to be invoked if the user taps on this cell in the row.
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
index 67bbfa1..1b49050 100644
--- 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
@@ -26,7 +26,7 @@
 import android.support.annotation.RestrictTo;
 
 import androidx.app.slice.Slice;
-import androidx.app.slice.SliceSpec;
+import androidx.app.slice.builders.SliceAction;
 
 
 /**
@@ -37,8 +37,8 @@
 
     /**
      */
-    public GridBuilderBasicImpl(Slice.Builder b, SliceSpec spec) {
-        super(b, spec);
+    public GridBuilderBasicImpl(@NonNull ListBuilderBasicImpl parent) {
+        super(parent.createChildBuilder(), null);
     }
 
     /**
@@ -77,9 +77,7 @@
     /**
      */
     @Override
-    public Slice buildIndividual() {
-        // Empty slice, nothing useful from a grid to basic.
-        return getBuilder().build();
+    public void setPrimaryAction(SliceAction action) {
     }
 
     /**
@@ -137,28 +135,14 @@
          */
         @NonNull
         @Override
-        public void addLargeImage(@NonNull Icon image) {
+        public void addImage(@NonNull Icon image, int imageMode) {
         }
 
         /**
          */
         @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) {
+        public void addImage(@Nullable Icon image, int imageMode, boolean isLoading) {
         }
 
         /**
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
index fe755bd..e116e08 100644
--- 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
@@ -19,10 +19,16 @@
 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_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_TITLE;
 import static android.support.annotation.RestrictTo.Scope.LIBRARY;
 
+import static androidx.app.slice.builders.GridBuilder.ICON_IMAGE;
+import static androidx.app.slice.builders.GridBuilder.LARGE_IMAGE;
+
 import android.app.PendingIntent;
 import android.graphics.drawable.Icon;
 import android.net.Uri;
@@ -30,8 +36,10 @@
 import android.support.annotation.Nullable;
 import android.support.annotation.RestrictTo;
 
+import java.util.ArrayList;
+
 import androidx.app.slice.Slice;
-import androidx.app.slice.SliceSpec;
+import androidx.app.slice.builders.SliceAction;
 
 /**
  * @hide
@@ -39,17 +47,34 @@
 @RestrictTo(LIBRARY)
 public class GridBuilderListV1Impl extends TemplateBuilderImpl implements GridBuilder {
 
+    private SliceAction mPrimaryAction;
+
     /**
      */
-    public GridBuilderListV1Impl(@NonNull Slice.Builder builder, SliceSpec spec) {
-        super(builder, spec);
+    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) {
-        builder.addHints(HINT_HORIZONTAL, HINT_LIST_ITEM);
     }
 
     /**
@@ -96,10 +121,8 @@
     /**
      */
     @Override
-    public Slice buildIndividual() {
-        return new Slice.Builder(getBuilder()).addHints(HINT_HORIZONTAL, HINT_LIST_ITEM)
-                .addSubSlice(getBuilder()
-                        .addHints(HINT_HORIZONTAL, HINT_LIST_ITEM).build()).build();
+    public void setPrimaryAction(SliceAction action) {
+        mPrimaryAction = action;
     }
 
     /**
@@ -162,37 +185,25 @@
          */
         @NonNull
         @Override
-        public void addLargeImage(@NonNull Icon image) {
-            addLargeImage(image, false /* isLoading */);
+        public void addImage(@NonNull Icon image, int imageMode) {
+            addImage(image, imageMode, 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];
+        public void addImage(@Nullable Icon image, int imageMode, boolean isLoading) {
+            ArrayList<String> hints = new ArrayList<>();
+            if (imageMode != ICON_IMAGE) {
+                hints.add(HINT_NO_TINT);
+            }
+            if (imageMode == LARGE_IMAGE) {
+                hints.add(HINT_LARGE);
+            }
+            if (isLoading) {
+                hints.add(HINT_PARTIAL);
+            }
             getBuilder().addIcon(image, null, hints);
         }
 
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
index d92083e..c16da2b 100644
--- 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
@@ -21,9 +21,12 @@
 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
  */
@@ -48,10 +51,10 @@
     void setHeader(TemplateBuilderImpl impl);
 
     /**
-     * Sets the group of actions for this template. These actions may be shown on the template in
-     * large or small formats.
+     * 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 setActions(TemplateBuilderImpl impl);
+    void addAction(SliceAction action);
 
     /**
      * Add an input range row to the list builder.
@@ -87,7 +90,7 @@
     /**
      * Sets the color to tint items displayed by this template (e.g. icons).
      */
-    void setColor(int color);
+    void setColor(@ColorInt int color);
 
     /**
      * Create a builder that implements {@link RowBuilder}.
@@ -110,19 +113,9 @@
      */
     TemplateBuilderImpl createHeaderBuilder(Uri uri);
     /**
-     * Create a builder that implements {@link ActionBuilder}.
-     */
-    TemplateBuilderImpl createActionBuilder();
-    /**
-     * Create a builder that implements {@link ActionBuilder}.
-     */
-    TemplateBuilderImpl createActionBuilder(Uri uri);
-
-    /**
      * Create a builder that implements {@link InputRangeBuilder}.
      */
     TemplateBuilderImpl createInputRangeBuilder();
-
     /**
      * Create a builder that implements {@link RangeBuilder}.
      */
@@ -196,7 +189,7 @@
          * 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(Icon icon, PendingIntent action);
+        void setTitleItem(SliceAction action);
 
         /**
          * Sets the title item to be a tappable icon. There can only be one title item, this will
@@ -206,12 +199,12 @@
          * to load this content in the background, in this case the template displays a placeholder
          * until updated.
          */
-        void setTitleItem(Icon icon, PendingIntent action, boolean isLoading);
+        void setTitleItem(SliceAction action, boolean isLoading);
 
         /**
          * Sets the action to be invoked if the user taps on the main content of the template.
          */
-        void setContentIntent(PendingIntent action);
+        void setPrimaryAction(SliceAction action);
 
         /**
          * Sets the title text.
@@ -263,7 +256,7 @@
         /**
          * Adds a tappable icon to be displayed at the end of the row.
          */
-        void addEndItem(Icon icon, PendingIntent action);
+        void addEndItem(SliceAction action);
 
         /**
          * Adds a tappable icon to be displayed at the end of the row.
@@ -272,23 +265,7 @@
          * to load this content in the background, in this case the template displays a placeholder
          * until updated.
          */
-        void addEndItem(Icon icon, PendingIntent action, boolean isLoading);
-
-        /**
-         * Adds a toggle action to the template with custom icons to represent checked and unchecked
-         * state.
-         */
-        void addToggle(PendingIntent action, boolean isChecked, Icon icon);
-
-        /**
-         * Adds a toggle action to the template with custom icons to represent checked and unchecked
-         * state.
-         * <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 addToggle(PendingIntent action, boolean isChecked, Icon icon, boolean isLoading);
+        void addEndItem(SliceAction action, boolean isLoading);
     }
 
 
@@ -316,27 +293,9 @@
         void setSummarySubtitle(CharSequence summarySubtitle);
 
         /**
-         * Sets the pending intent to activate when the header is activated.
+         * Sets the action to invoke when the header is activated.
          */
-        void setContentIntent(PendingIntent intent);
-    }
-
-    /**
-     * Builder to construct a group of actions.
-     */
-    public interface ActionBuilder {
-
-        /**
-         * Adds an action to this builder.
-         *
-         * @param action the pending intent to send when the action is activated.
-         * @param actionIcon the icon to display for this action.
-         * @param contentDescription the content description to use for accessibility.
-         * @param priority what priority to display this action in, with the lowest priority having
-         *                 the highest ranking.
-         */
-        void addAction(PendingIntent action, Icon actionIcon, CharSequence contentDescription,
-                int priority);
+        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
index 8657c90..b47e7f2 100644
--- 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
@@ -21,11 +21,13 @@
 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
@@ -56,7 +58,7 @@
     /**
      */
     @Override
-    public void setActions(TemplateBuilderImpl impl) {
+    public void addAction(SliceAction impl) {
         // Do nothing.
     }
 
@@ -92,7 +94,7 @@
     /**
      */
     @Override
-    public void setColor(int color) {
+    public void setColor(@ColorInt int color) {
     }
 
     /**
@@ -113,7 +115,7 @@
      */
     @Override
     public TemplateBuilderImpl createGridBuilder() {
-        return new GridBuilderBasicImpl(createChildBuilder(), null);
+        return new GridBuilderBasicImpl(this);
     }
 
     @Override
@@ -127,16 +129,6 @@
     }
 
     @Override
-    public TemplateBuilderImpl createActionBuilder() {
-        return new ActionBuilderImpl(this);
-    }
-
-    @Override
-    public TemplateBuilderImpl createActionBuilder(Uri uri) {
-        return new ActionBuilderImpl(uri);
-    }
-
-    @Override
     public TemplateBuilderImpl createInputRangeBuilder() {
         return new ListBuilderV1Impl.InputRangeBuilderImpl(getBuilder());
     }
@@ -157,9 +149,6 @@
      */
     public static class RowBuilderImpl extends TemplateBuilderImpl
             implements ListBuilder.RowBuilder {
-        private Icon mIcon;
-        private CharSequence mTitle;
-        private CharSequence mSubtitle;
 
         /**
          */
@@ -190,29 +179,14 @@
         /**
          */
         @Override
-        public void addEndItem(Icon icon, PendingIntent action) {
+        public void addEndItem(SliceAction action) {
 
         }
 
         /**
          */
         @Override
-        public void addEndItem(Icon icon, PendingIntent action, boolean isLoading) {
-
-        }
-
-        /**
-         */
-        @Override
-        public void addToggle(PendingIntent action, boolean isChecked, Icon icon) {
-
-        }
-
-        /**
-         */
-        @Override
-        public void addToggle(PendingIntent action, boolean isChecked, Icon icon,
-                boolean isLoading) {
+        public void addEndItem(SliceAction action, boolean isLoading) {
 
         }
 
@@ -227,7 +201,6 @@
          */
         @Override
         public void setTitleItem(Icon icon) {
-            mIcon = icon;
         }
 
         /**
@@ -240,21 +213,20 @@
         /**
          */
         @Override
-        public void setTitleItem(Icon icon, PendingIntent action) {
-            mIcon = icon;
+        public void setTitleItem(SliceAction action) {
         }
 
         /**
          */
         @Override
-        public void setTitleItem(Icon icon, PendingIntent action, boolean isLoading) {
+        public void setTitleItem(SliceAction action, boolean isLoading) {
 
         }
 
         /**
          */
         @Override
-        public void setContentIntent(PendingIntent action) {
+        public void setPrimaryAction(SliceAction action) {
 
         }
 
@@ -262,7 +234,6 @@
          */
         @Override
         public void setTitle(CharSequence title) {
-            mTitle = title;
         }
 
         /**
@@ -276,7 +247,6 @@
          */
         @Override
         public void setSubtitle(CharSequence subtitle) {
-            mSubtitle = subtitle;
         }
 
         /**
@@ -349,40 +319,7 @@
         /**
          */
         @Override
-        public void setContentIntent(PendingIntent intent) {
-
-        }
-    }
-
-    /**
-     */
-    public static class ActionBuilderImpl extends TemplateBuilderImpl
-            implements ListBuilder.ActionBuilder {
-
-        /**
-         */
-        public ActionBuilderImpl(@NonNull ListBuilderBasicImpl parent) {
-            super(parent.createChildBuilder(), null);
-        }
-
-        /**
-         */
-        public ActionBuilderImpl(@NonNull Uri uri) {
-            super(new Slice.Builder(uri), null);
-        }
-
-        /**
-         */
-        @Override
-        public void apply(Slice.Builder builder) {
-
-        }
-
-        /**
-         */
-        @Override
-        public void addAction(PendingIntent action, Icon actionIcon,
-                CharSequence contentDescription, int priority) {
+        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
index 4ec4ac0..0a73f34 100644
--- 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
@@ -22,18 +22,13 @@
 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.Slice.SUBTYPE_COLOR;
-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_TEXT;
-import static android.app.slice.SliceItem.FORMAT_TIMESTAMP;
 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;
@@ -41,15 +36,18 @@
 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
@@ -57,7 +55,7 @@
 @RestrictTo(LIBRARY)
 public class ListBuilderV1Impl extends TemplateBuilderImpl implements ListBuilder {
 
-    private Slice mSliceActions;
+    private List<Slice> mSliceActions;
     private Slice mSliceHeader;
 
     /**
@@ -74,7 +72,11 @@
             builder.addSubSlice(mSliceHeader);
         }
         if (mSliceActions != null) {
-            builder.addSubSlice(mSliceActions);
+            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());
         }
     }
 
@@ -105,8 +107,12 @@
     /**
      */
     @Override
-    public void setActions(@NonNull TemplateBuilderImpl builder) {
-        mSliceActions = builder.build();
+    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
@@ -217,7 +223,7 @@
      */
     @NonNull
     @Override
-    public void setColor(int color) {
+    public void setColor(@ColorInt int color) {
         getBuilder().addInt(color, SUBTYPE_COLOR);
     }
 
@@ -250,7 +256,7 @@
      */
     @Override
     public TemplateBuilderImpl createGridBuilder() {
-        return new GridBuilderListV1Impl(createChildBuilder(), null);
+        return new GridBuilderListV1Impl(this);
     }
 
     /**
@@ -265,26 +271,16 @@
         return new HeaderBuilderImpl(uri);
     }
 
-    @Override
-    public TemplateBuilderImpl createActionBuilder() {
-        return new ActionBuilderImpl(this);
-    }
-
-    @Override
-    public TemplateBuilderImpl createActionBuilder(Uri uri) {
-        return new ActionBuilderImpl(uri);
-    }
-
     /**
      */
     public static class RowBuilderImpl extends TemplateBuilderImpl
             implements ListBuilder.RowBuilder {
 
-        private PendingIntent mContentIntent;
+        private SliceAction mPrimaryAction;
         private SliceItem mTitleItem;
         private SliceItem mSubtitleItem;
-        private SliceItem mStartItem;
-        private ArrayList<SliceItem> mEndItems = new ArrayList<>();
+        private Slice mStartItem;
+        private ArrayList<Slice> mEndItems = new ArrayList<>();
 
         /**
          */
@@ -309,7 +305,8 @@
         @NonNull
         @Override
         public void setTitleItem(long timeStamp) {
-            mStartItem = new SliceItem(timeStamp, FORMAT_TIMESTAMP, null, new String[]{HINT_TITLE});
+            mStartItem = new Slice.Builder(getBuilder())
+                    .addTimestamp(timeStamp, null).addHints(HINT_TITLE).build();
         }
 
         /**
@@ -324,38 +321,38 @@
          */
         @Override
         public void setTitleItem(@Nullable Icon icon, boolean isLoading) {
-            mStartItem = new SliceItem(icon, FORMAT_IMAGE, null, new String[]{HINT_TITLE});
+            Slice.Builder sb = new Slice.Builder(getBuilder()).addIcon(icon, null /* subtype */);
             if (isLoading) {
-                mStartItem.addHint(HINT_PARTIAL);
+                sb.addHints(HINT_PARTIAL);
             }
+            mStartItem = sb.addHints(HINT_TITLE).build();
         }
 
         /**
          */
         @NonNull
         @Override
-        public void setTitleItem(@NonNull Icon icon, @NonNull PendingIntent action) {
-            setTitleItem(icon, action, false /* isLoading */);
+        public void setTitleItem(@NonNull SliceAction action) {
+            setTitleItem(action, false /* isLoading */);
         }
 
         /**
          */
         @Override
-        public void setTitleItem(Icon icon, PendingIntent action, boolean isLoading) {
-            Slice actionSlice = new Slice.Builder(getBuilder()).addIcon(icon, null).build();
-            mStartItem = new SliceItem(action, actionSlice, FORMAT_ACTION, null,
-                    new String[]{HINT_TITLE});
+        public void setTitleItem(SliceAction action, boolean isLoading) {
+            Slice.Builder sb = new Slice.Builder(getBuilder()).addHints(HINT_TITLE);
             if (isLoading) {
-                mStartItem.addHint(HINT_PARTIAL);
+                sb.addHints(HINT_PARTIAL);
             }
+            mStartItem = action.buildSlice(sb);
         }
 
         /**
          */
         @NonNull
         @Override
-        public void setContentIntent(@NonNull PendingIntent action) {
-            mContentIntent = action;
+        public void setPrimaryAction(@NonNull SliceAction action) {
+            mPrimaryAction = action;
         }
 
         /**
@@ -399,7 +396,8 @@
         @NonNull
         @Override
         public void addEndItem(long timeStamp) {
-            mEndItems.add(new SliceItem(timeStamp, FORMAT_TIMESTAMP, null, new String[0]));
+            mEndItems.add(new Slice.Builder(getBuilder()).addTimestamp(timeStamp,
+                    null, new String[0]).build());
         }
 
         /**
@@ -414,73 +412,39 @@
          */
         @Override
         public void addEndItem(Icon icon, boolean isLoading) {
-            SliceItem item = new SliceItem(icon, FORMAT_IMAGE, null,
-                    new String[] {HINT_NO_TINT, HINT_LARGE});
+            Slice.Builder sb = new Slice.Builder(getBuilder()).addIcon(icon, null /* subType */,
+                    HINT_NO_TINT, HINT_LARGE);
             if (isLoading) {
-                item.addHint(HINT_PARTIAL);
+                sb.addHints(HINT_PARTIAL);
             }
-            mEndItems.add(item);
+            mEndItems.add(sb.build());
         }
 
         /**
          */
         @NonNull
         @Override
-        public void addEndItem(@NonNull Icon icon, @NonNull PendingIntent action) {
-            addEndItem(icon, action, false /* isLoading */);
+        public void addEndItem(@NonNull SliceAction action) {
+            addEndItem(action, false /* isLoading */);
         }
 
         /**
          */
         @Override
-        public void addEndItem(Icon icon, PendingIntent action, boolean isLoading) {
-            Slice actionSlice = new Slice.Builder(getBuilder()).addIcon(icon, null).build();
-            SliceItem item = new SliceItem(action, actionSlice, FORMAT_ACTION, null,
-                    new String[0]);
+        public void addEndItem(@NonNull SliceAction action, boolean isLoading) {
+            Slice.Builder sb = new Slice.Builder(getBuilder());
             if (isLoading) {
-                item.addHint(HINT_PARTIAL);
+                sb.addHints(HINT_PARTIAL);
             }
-            mEndItems.add(item);
-        }
-
-        /**
-         */
-        @NonNull
-        @Override
-        public void addToggle(@NonNull PendingIntent action, boolean isChecked,
-                @NonNull Icon icon) {
-            addToggle(action, isChecked, icon, false /* isLoading */);
-        }
-
-        @Override
-        public void addToggle(PendingIntent action, boolean isChecked, Icon icon,
-                boolean isLoading) {
-            @Slice.SliceHint String[] hints = isChecked
-                    ? new String[] {HINT_SELECTED}
-                    : new String[0];
-            Slice.Builder actionSliceBuilder = new Slice.Builder(getBuilder()).addHints(hints);
-            if (icon != null) {
-                actionSliceBuilder.addIcon(icon, null);
-            }
-            Slice actionSlice = actionSliceBuilder.build();
-            SliceItem item = new SliceItem(action, actionSlice, FORMAT_ACTION, SUBTYPE_TOGGLE,
-                    hints);
-            if (isLoading) {
-                item.addHint(HINT_PARTIAL);
-            }
-            mEndItems.add(item);
+            mEndItems.add(action.buildSlice(sb));
         }
 
         /**
          */
         @Override
         public void apply(Slice.Builder b) {
-            Slice.Builder wrapped = b;
-            if (mContentIntent != null) {
-                b = new Slice.Builder(wrapped);
-            }
             if (mStartItem != null) {
-                b.addItem(mStartItem);
+                b.addSubSlice(mStartItem);
             }
             if (mTitleItem != null) {
                 b.addItem(mTitleItem);
@@ -489,13 +453,15 @@
                 b.addItem(mSubtitleItem);
             }
             for (int i = 0; i < mEndItems.size(); i++) {
-                SliceItem item = mEndItems.get(i);
-                b.addItem(item);
+                Slice item = mEndItems.get(i);
+                b.addSubSlice(item);
             }
-            if (mContentIntent != null) {
-                wrapped.addAction(mContentIntent, b.build(), null);
+            if (mPrimaryAction != null) {
+                Slice.Builder sb = new Slice.Builder(
+                        getBuilder()).addHints(HINT_TITLE, HINT_SHORTCUT);
+                b.addSubSlice(mPrimaryAction.buildSlice(sb), null);
             }
-            wrapped.addHints(HINT_LIST_ITEM);
+            b.addHints(HINT_LIST_ITEM);
         }
     }
 
@@ -507,7 +473,7 @@
         private CharSequence mTitle;
         private CharSequence mSubtitle;
         private CharSequence mSummarySubtitle;
-        private PendingIntent mContentIntent;
+        private SliceAction mPrimaryAction;
 
         /**
          */
@@ -525,10 +491,6 @@
          */
         @Override
         public void apply(Slice.Builder b) {
-            Slice.Builder wrapped = b;
-            if (mContentIntent != null) {
-                b = new Slice.Builder(wrapped);
-            }
             if (mTitle != null) {
                 b.addText(mTitle, null /* subtype */, HINT_TITLE);
             }
@@ -538,8 +500,10 @@
             if (mSummarySubtitle != null) {
                 b.addText(mSummarySubtitle, null /* subtype */, HINT_SUMMARY);
             }
-            if (mContentIntent != null) {
-                wrapped.addAction(mContentIntent, b.build(), null /* subtype */);
+            if (mPrimaryAction != null) {
+                Slice.Builder sb = new Slice.Builder(
+                        getBuilder()).addHints(HINT_TITLE, HINT_SHORTCUT);
+                b.addSubSlice(mPrimaryAction.buildSlice(sb), null /* subtype */);
             }
         }
 
@@ -567,45 +531,8 @@
         /**
          */
         @Override
-        public void setContentIntent(PendingIntent intent) {
-            mContentIntent = intent;
-        }
-    }
-
-    /**
-     */
-    public static class ActionBuilderImpl extends TemplateBuilderImpl
-            implements ListBuilder.ActionBuilder {
-
-        /**
-         */
-        public ActionBuilderImpl(@NonNull ListBuilderV1Impl parent) {
-            super(parent.createChildBuilder(), null);
-        }
-
-        /**
-         */
-        public ActionBuilderImpl(@NonNull Uri uri) {
-            super(new Slice.Builder(uri), null);
-        }
-
-        /**
-         */
-        @Override
-        public void apply(Slice.Builder builder) {
-            builder.addHints(HINT_ACTIONS);
-        }
-
-        /**
-         */
-        @Override
-        public void addAction(PendingIntent action, Icon actionIcon,
-                CharSequence contentDescription, int priority) {
-            getBuilder().addAction(action, new Slice.Builder(getBuilder())
-                    .addIcon(actionIcon, null /* subtype */)
-                    .addInt(priority, SUBTYPE_PRIORITY /* subtype */)
-                    .addText(contentDescription, SUBTYPE_CONTENT_DESCRIPTION)
-                    .addHints(HINT_ACTIONS).build(), null /* subtype */);
+        public void setPrimaryAction(SliceAction action) {
+            mPrimaryAction = action;
         }
     }
 }
diff --git a/slices/core/build.gradle b/slices/core/build.gradle
index 879b409..8087ab4 100644
--- a/slices/core/build.gradle
+++ b/slices/core/build.gradle
@@ -36,7 +36,7 @@
     name = "Common utilities for slices"
     publish = true
     mavenVersion = LibraryVersions.SUPPORT_LIBRARY
-    mavenGroup = LibraryGroups.SLICES
+    mavenGroup = LibraryGroups.SUPPORT
     inceptionYear = "2017"
     description = "The slices core library provides utilities for the slices view and provider libraries"
     minSdkVersion = 24
diff --git a/slices/core/src/androidTest/NO_DOCS b/slices/core/src/androidTest/NO_DOCS
deleted file mode 100644
index 092a39c..0000000
--- a/slices/core/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/slices/core/src/main/java/androidx/app/slice/Slice.java b/slices/core/src/main/java/androidx/app/slice/Slice.java
index 779460e..966c877 100644
--- a/slices/core/src/main/java/androidx/app/slice/Slice.java
+++ b/slices/core/src/main/java/androidx/app/slice/Slice.java
@@ -25,6 +25,7 @@
 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;
@@ -34,14 +35,14 @@
 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.content.ContentProvider;
+import android.app.slice.SliceManager;
 import android.content.Context;
-import android.content.Intent;
 import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.os.Bundle;
@@ -80,7 +81,8 @@
      */
     @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_HORIZONTAL, HINT_NO_TINT, HINT_PARTIAL, HINT_SUMMARY, HINT_SEE_MORE,
+            HINT_SHORTCUT})
     public @interface SliceHint{ }
 
     private final SliceItem[] mItems;
@@ -448,39 +450,7 @@
     @TargetApi(28)
     private static Slice callBindSlice(Context context, Uri uri,
             List<SliceSpec> supportedSpecs) {
-        return SliceConvert.wrap(android.app.slice.Slice.bindSlice(
-                context.getContentResolver(), uri, unwrap(supportedSpecs)));
-    }
-
-
-    /**
-     * Turns a slice intent into slice content. Expects an explicit intent. If there is no
-     * {@link ContentProvider} associated with the given intent this will throw
-     * {@link IllegalArgumentException}.
-     *
-     * @hide
-     * @param context The context to use.
-     * @param intent The intent associated with a slice.
-     * @return The Slice provided by the app or null if none is given.
-     * @see Slice
-     * @see SliceProvider#onMapIntentToUri(Intent)
-     * @see Intent
-     */
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    @SuppressWarnings("NewApi")
-    public static @Nullable Slice bindSlice(Context context, @NonNull Intent intent,
-                List<SliceSpec> supportedSpecs) {
-        if (BuildCompat.isAtLeastP()) {
-            return callBindSlice(context, intent, supportedSpecs);
-        } else {
-            return SliceProviderCompat.bindSlice(context, intent, supportedSpecs);
-        }
-    }
-
-    @TargetApi(28)
-    private static Slice callBindSlice(Context context, Intent intent,
-            List<SliceSpec> supportedSpecs) {
-        return SliceConvert.wrap(android.app.slice.Slice.bindSlice(
-                context, intent, unwrap(supportedSpecs)));
+        return SliceConvert.wrap(context.getSystemService(SliceManager.class)
+                .bindSlice(uri, unwrap(supportedSpecs)));
     }
 }
diff --git a/slices/core/src/main/java/androidx/app/slice/SliceSpecs.java b/slices/core/src/main/java/androidx/app/slice/SliceSpecs.java
index ed4658d..6629f21 100644
--- a/slices/core/src/main/java/androidx/app/slice/SliceSpecs.java
+++ b/slices/core/src/main/java/androidx/app/slice/SliceSpecs.java
@@ -41,11 +41,4 @@
      * a source of where the message came from.
      */
     public static final SliceSpec MESSAGING = new SliceSpec("androidx.app.slice.MESSAGING", 1);
-
-    /**
-     * Grid template.
-     * Lists can contain grids, so use the same spec for both. Grid needs a spec to use because
-     * it can be a top level builder.
-     */
-    public static final SliceSpec GRID = LIST;
 }
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
index d1a8e65..be3b88b 100644
--- a/slices/core/src/main/java/androidx/app/slice/compat/SliceProviderCompat.java
+++ b/slices/core/src/main/java/androidx/app/slice/compat/SliceProviderCompat.java
@@ -18,7 +18,6 @@
 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;
@@ -44,6 +43,7 @@
 import android.support.annotation.Nullable;
 import android.support.annotation.RestrictTo;
 import android.support.annotation.RestrictTo.Scope;
+import android.support.v4.util.Preconditions;
 import android.util.Log;
 
 import java.util.ArrayList;
@@ -54,6 +54,7 @@
 import androidx.app.slice.SliceProvider;
 import androidx.app.slice.SliceSpec;
 import androidx.app.slice.core.R;
+import androidx.app.slice.core.SliceHints;
 
 /**
  * @hide
@@ -69,6 +70,7 @@
     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 METHOD_MAP_ONLY_INTENT = "map_only";
 
     public static final String EXTRA_INTENT = "slice_intent";
     public static final String EXTRA_SLICE = "slice";
@@ -156,8 +158,8 @@
         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(),
+                getContext().enforceUriPermission(uri, Binder.getCallingPid(),
+                        Binder.getCallingUid(),
                         Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
                         "Slice binding requires the permission BIND_SLICE");
             }
@@ -168,10 +170,6 @@
             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();
@@ -183,6 +181,12 @@
                 b.putParcelable(EXTRA_SLICE, null);
             }
             return b;
+        } else if (method.equals(METHOD_MAP_INTENT)) {
+            Intent intent = extras.getParcelable(EXTRA_INTENT);
+            Uri uri = mSliceProvider.onMapIntentToUri(intent);
+            Bundle b = new Bundle();
+            b.putParcelable(EXTRA_SLICE, uri);
+            return b;
         } else if (method.equals(METHOD_PIN)) {
             Uri uri = extras.getParcelable(EXTRA_BIND_URI);
             List<SliceSpec> specs = getSpecs(extras);
@@ -524,4 +528,54 @@
             provider.close();
         }
     }
+
+    /**
+     * Compat version of {@link android.app.slice.SliceManager#mapIntentToUri}.
+     */
+    public static Uri mapIntentToUri(Context context, Intent intent) {
+        Preconditions.checkNotNull(intent, "intent");
+        Preconditions.checkArgument(intent.getComponent() != null || intent.getPackage() != null,
+                String.format("Slice intent must be explicit %s", intent));
+        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 intentData;
+        }
+        // Otherwise ask the app
+        List<ResolveInfo> providers =
+                context.getPackageManager().queryIntentContentProviders(intent, 0);
+        if (providers == null || providers.isEmpty()) {
+            // There are no providers, see if this activity has a direct link.
+            ResolveInfo resolve = context.getPackageManager().resolveActivity(intent,
+                    PackageManager.GET_META_DATA);
+            if (resolve != null && resolve.activityInfo != null
+                    && resolve.activityInfo.metaData != null
+                    && resolve.activityInfo.metaData.containsKey(SliceHints.SLICE_METADATA_KEY)) {
+                return Uri.parse(
+                        resolve.activityInfo.metaData.getString(SliceHints.SLICE_METADATA_KEY));
+            }
+            return null;
+        }
+        String authority = providers.get(0).providerInfo.authority;
+        Uri uri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
+                .authority(authority).build();
+        try (ContentProviderClient provider = resolver.acquireContentProviderClient(uri)) {
+            if (provider == null) {
+                throw new IllegalArgumentException("Unknown URI " + uri);
+            }
+            Bundle extras = new Bundle();
+            extras.putParcelable(EXTRA_INTENT, intent);
+            final Bundle res = provider.call(METHOD_MAP_ONLY_INTENT, null, extras);
+            if (res == null) {
+                return null;
+            }
+            return res.getParcelable(EXTRA_SLICE);
+        } catch (RemoteException e) {
+            // Arbitrary and not worth documenting, as Activity
+            // Manager will kill this process shortly anyway.
+            return null;
+        }
+    }
 }
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
index e566825..09f9540 100644
--- a/slices/core/src/main/java/androidx/app/slice/core/SliceHints.java
+++ b/slices/core/src/main/java/androidx/app/slice/core/SliceHints.java
@@ -45,4 +45,13 @@
      * 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";
+
+    /**
+     * The meta-data key that allows an activity to easily be linked directly to a slice.
+     * <p>
+     * An activity can be statically linked to a slice uri by including a meta-data item
+     * for this key that contains a valid slice uri for the same application declaring
+     * the activity.
+     */
+    public static final String SLICE_METADATA_KEY = "android.metadata.SLICE_URI";
 }
diff --git a/slices/core/src/main/res/values-af/strings.xml b/slices/core/src/main/res/values-af/strings.xml
new file mode 100644
index 0000000..1619490
--- /dev/null
+++ b/slices/core/src/main/res/values-af/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> wil <xliff:g id="APP_2">%2$s</xliff:g>-skyfies wys"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Laat <xliff:g id="APP_0">%1$s</xliff:g> toe om <xliff:g id="APP_2">%2$s</xliff:g>-skyfies te wys?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– Dit kan inligting in <xliff:g id="APP">%1$s</xliff:g> lees"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– Dit kan handelinge binne <xliff:g id="APP">%1$s</xliff:g> uitvoer"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Laat <xliff:g id="APP">%1$s</xliff:g> toe om skyfies uit enige program te wys"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Laat toe"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Weier"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-am/strings.xml b/slices/core/src/main/res/values-am/strings.xml
new file mode 100644
index 0000000..c187e0f
--- /dev/null
+++ b/slices/core/src/main/res/values-am/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> የ<xliff:g id="APP_2">%2$s</xliff:g> ቁራጮችን ማሳየት ይፈልጋል"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> የ<xliff:g id="APP_2">%2$s</xliff:g> ቁራጮችን እንዲያሳይ ይፈቀድለት?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- ከ<xliff:g id="APP">%1$s</xliff:g> የመጣ መረጃን ማንበብ ይችላል"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- በ<xliff:g id="APP">%1$s</xliff:g> ውስጥ እርምጃዎችን መውሰድ ይችላል"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"<xliff:g id="APP">%1$s</xliff:g> ከማንኛውም መተግበሪያ የመጡ ቁራጮችን እንዲያሳይ ፍቀድለት"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"ፍቀድ"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"ከልክል"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-ar/strings.xml b/slices/core/src/main/res/values-ar/strings.xml
new file mode 100644
index 0000000..b5de01c
--- /dev/null
+++ b/slices/core/src/main/res/values-ar/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"يريد تطبيق <xliff:g id="APP_0">%1$s</xliff:g> عرض شرائح تطبيق <xliff:g id="APP_2">%2$s</xliff:g>."</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"هل تريد السماح لتطبيق <xliff:g id="APP_0">%1$s</xliff:g> بعرض شرائح <xliff:g id="APP_2">%2$s</xliff:g>؟"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- إمكانية قراءة المعلومات من <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- إمكانية اتخاذ إجراءات داخل <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"السماح لتطبيق <xliff:g id="APP">%1$s</xliff:g> بعرض شرائح من أي تطبيق"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"سماح"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"رفض"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-az/strings.xml b/slices/core/src/main/res/values-az/strings.xml
new file mode 100644
index 0000000..ff7be30
--- /dev/null
+++ b/slices/core/src/main/res/values-az/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> <xliff:g id="APP_2">%2$s</xliff:g> tətbiqindən hissələr göstərmək istəyir"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> tətbiqinə <xliff:g id="APP_2">%2$s</xliff:g> hissələrini göstərmək üçün icazə verilsin?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- <xliff:g id="APP">%1$s</xliff:g> tətbiqindən məlumat oxuya bilər"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- <xliff:g id="APP">%1$s</xliff:g> daxilində əməliyyatlar edə bilər"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"<xliff:g id="APP">%1$s</xliff:g> tətbiqinə istənilən tətbiqdən hissə göstərmək icazəsi verin"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"İcazə verin"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Rədd edin"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-b+sr+Latn/strings.xml b/slices/core/src/main/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..95c1692
--- /dev/null
+++ b/slices/core/src/main/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"Aplikacija <xliff:g id="APP_0">%1$s</xliff:g> želi da prikazuje isečke iz aplikacije <xliff:g id="APP_2">%2$s</xliff:g>"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Želite li da dozvolite aplikaciji <xliff:g id="APP_0">%1$s</xliff:g> da prikazuje isečke iz aplikacije <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– Može da čita podatke iz aplikacije <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– Može da obavlja radnje u aplikaciji <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Dozvoli aplikaciji <xliff:g id="APP">%1$s</xliff:g> da prikazuje isečke iz bilo koje aplikacije"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Dozvoli"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Odbij"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-be/strings.xml b/slices/core/src/main/res/values-be/strings.xml
new file mode 100644
index 0000000..c9fc9a8
--- /dev/null
+++ b/slices/core/src/main/res/values-be/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"Праграма <xliff:g id="APP_0">%1$s</xliff:g> запытвае дазвол на паказ зрэзаў праграмы <xliff:g id="APP_2">%2$s</xliff:g>"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Дазволіць праграме <xliff:g id="APP_0">%1$s</xliff:g> паказваць зрэзы праграмы <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Можа счытваць інфармацыю з праграмы <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Можа выконваць дзеянні ў праграме <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Дазволіць праграме <xliff:g id="APP">%1$s</xliff:g> паказваць зрэзы іншых праграм"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Дазволіць"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Адмовіць"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-bg/strings.xml b/slices/core/src/main/res/values-bg/strings.xml
new file mode 100644
index 0000000..cb6f067
--- /dev/null
+++ b/slices/core/src/main/res/values-bg/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> иска да показва части от <xliff:g id="APP_2">%2$s</xliff:g>"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Ще разрешите ли на <xliff:g id="APP_0">%1$s</xliff:g> да показва части от <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– Може да чете информация от <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– Може да предприема действия в/ъв <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Разрешаване на <xliff:g id="APP">%1$s</xliff:g> да показва части от което и да е приложение"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Разрешаване"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Отказ"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-bn/strings.xml b/slices/core/src/main/res/values-bn/strings.xml
new file mode 100644
index 0000000..cfa569d
--- /dev/null
+++ b/slices/core/src/main/res/values-bn/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> অ্যাপটি <xliff:g id="APP_2">%2$s</xliff:g> এর অংশ দেখাতে চায়"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> অ্যাপটিকে <xliff:g id="APP_2">%2$s</xliff:g> এর অংশ দেখানোর অনুমতি দেবেন?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- এটি <xliff:g id="APP">%1$s</xliff:g> এর তথ্য অ্যাক্সেস করতে পারবে"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- এটি <xliff:g id="APP">%1$s</xliff:g> এর মধ্যে কাজ করতে পারবে"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"<xliff:g id="APP">%1$s</xliff:g> অ্যাপটিকে যেকোনও অ্যাপের অংশ দেখাতে দিন"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"অনুমতি দিন"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"খারিজ করুন"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-bs/strings.xml b/slices/core/src/main/res/values-bs/strings.xml
new file mode 100644
index 0000000..a224ac6
--- /dev/null
+++ b/slices/core/src/main/res/values-bs/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"Aplikacija <xliff:g id="APP_0">%1$s</xliff:g> želi prikazati isječke aplikacije <xliff:g id="APP_2">%2$s</xliff:g>"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Dozvoliti aplikaciji <xliff:g id="APP_0">%1$s</xliff:g> prikazivanje isječaka aplikacije <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Može čitati informacije iz aplikacije <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Može poduzeti radnje unutar aplikacije <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Dozvoli aplikaciji <xliff:g id="APP">%1$s</xliff:g> prikazivanje isječaka iz svake aplikacije"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Dozvoli"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Odbij"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-ca/strings.xml b/slices/core/src/main/res/values-ca/strings.xml
new file mode 100644
index 0000000..0c953cf
--- /dev/null
+++ b/slices/core/src/main/res/values-ca/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> vol mostrar porcions de l\'aplicació <xliff:g id="APP_2">%2$s</xliff:g>"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Vols permetre que <xliff:g id="APP_0">%1$s</xliff:g> mostri porcions de l\'aplicació <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Pot llegir informació de l\'aplicació <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Pot dur a terme accions dins de l\'aplicació <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Permet que <xliff:g id="APP">%1$s</xliff:g> mostri porcions de qualsevol aplicació"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Permet"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Denega"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-cs/strings.xml b/slices/core/src/main/res/values-cs/strings.xml
new file mode 100644
index 0000000..6db0934
--- /dev/null
+++ b/slices/core/src/main/res/values-cs/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"Aplikace <xliff:g id="APP_0">%1$s</xliff:g> chce zobrazovat ukázky z aplikace <xliff:g id="APP_2">%2$s</xliff:g>"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Povolit aplikaci <xliff:g id="APP_0">%1$s</xliff:g> zobrazovat ukázky z aplikace <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– Může číst informace z aplikace <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– Může provádět akce v aplikaci <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Povolit aplikaci <xliff:g id="APP">%1$s</xliff:g> zobrazovat ukázky z libovolné aplikace"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Povolit"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Zamítnout"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-da/strings.xml b/slices/core/src/main/res/values-da/strings.xml
new file mode 100644
index 0000000..70f1a22
--- /dev/null
+++ b/slices/core/src/main/res/values-da/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> anmoder om tilladelse til at vise eksempler fra <xliff:g id="APP_2">%2$s</xliff:g>"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Vil du give <xliff:g id="APP_0">%1$s</xliff:g> tilladelse til at vise eksempler fra <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Den kan læse oplysninger fra <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Den kan foretage handlinger i <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Tillad, at <xliff:g id="APP">%1$s</xliff:g> viser eksempler fra enhver app"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Tillad"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Afvis"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-de/strings.xml b/slices/core/src/main/res/values-de/strings.xml
new file mode 100644
index 0000000..89ce98e
--- /dev/null
+++ b/slices/core/src/main/res/values-de/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> möchte Teile von <xliff:g id="APP_2">%2$s</xliff:g> anzeigen"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> erlauben, Teile von <xliff:g id="APP_2">%2$s</xliff:g> anzuzeigen?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– Darf Informationen aus <xliff:g id="APP">%1$s</xliff:g> lesen"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– Darf Aktionen in <xliff:g id="APP">%1$s</xliff:g> ausführen"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"<xliff:g id="APP">%1$s</xliff:g> darf Teile aus jeder beliebigen App anzeigen"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Zulassen"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Ablehnen"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-el/strings.xml b/slices/core/src/main/res/values-el/strings.xml
new file mode 100644
index 0000000..ed0b624
--- /dev/null
+++ b/slices/core/src/main/res/values-el/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"Η εφαρμογή <xliff:g id="APP_0">%1$s</xliff:g> θέλει να εμφανίζει τμήματα της εφαρμογής <xliff:g id="APP_2">%2$s</xliff:g>"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Να επιτρέπεται στην εφαρμογή <xliff:g id="APP_0">%1$s</xliff:g> να εμφανίζει τμήματα της εφαρμογής <xliff:g id="APP_2">%2$s</xliff:g>;"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Μπορεί να διαβάζει πληροφορίες από την εφαρμογή <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Μπορεί να εκτελεί ενέργειες εντός της εφαρμογής <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Να επιτρέπεται στην εφαρμογή <xliff:g id="APP">%1$s</xliff:g> να εμφανίζει τμήματα από οποιαδήποτε εφαρμογή"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Να επιτρέπεται"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Να μην επιτρέπεται"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-en-rAU/strings.xml b/slices/core/src/main/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000..d47c9ec
--- /dev/null
+++ b/slices/core/src/main/res/values-en-rAU/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> wants to show <xliff:g id="APP_2">%2$s</xliff:g> slices"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Allow <xliff:g id="APP_0">%1$s</xliff:g> to show <xliff:g id="APP_2">%2$s</xliff:g> slices?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– It can read information from <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– It can take actions inside <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Allow <xliff:g id="APP">%1$s</xliff:g> to show slices from any app"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Allow"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Deny"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-en-rCA/strings.xml b/slices/core/src/main/res/values-en-rCA/strings.xml
new file mode 100644
index 0000000..d47c9ec
--- /dev/null
+++ b/slices/core/src/main/res/values-en-rCA/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> wants to show <xliff:g id="APP_2">%2$s</xliff:g> slices"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Allow <xliff:g id="APP_0">%1$s</xliff:g> to show <xliff:g id="APP_2">%2$s</xliff:g> slices?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– It can read information from <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– It can take actions inside <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Allow <xliff:g id="APP">%1$s</xliff:g> to show slices from any app"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Allow"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Deny"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-en-rGB/strings.xml b/slices/core/src/main/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..d47c9ec
--- /dev/null
+++ b/slices/core/src/main/res/values-en-rGB/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> wants to show <xliff:g id="APP_2">%2$s</xliff:g> slices"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Allow <xliff:g id="APP_0">%1$s</xliff:g> to show <xliff:g id="APP_2">%2$s</xliff:g> slices?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– It can read information from <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– It can take actions inside <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Allow <xliff:g id="APP">%1$s</xliff:g> to show slices from any app"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Allow"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Deny"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-en-rIN/strings.xml b/slices/core/src/main/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..d47c9ec
--- /dev/null
+++ b/slices/core/src/main/res/values-en-rIN/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> wants to show <xliff:g id="APP_2">%2$s</xliff:g> slices"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Allow <xliff:g id="APP_0">%1$s</xliff:g> to show <xliff:g id="APP_2">%2$s</xliff:g> slices?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– It can read information from <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– It can take actions inside <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Allow <xliff:g id="APP">%1$s</xliff:g> to show slices from any app"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Allow"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Deny"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-en-rXC/strings.xml b/slices/core/src/main/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000..e65cf74
--- /dev/null
+++ b/slices/core/src/main/res/values-en-rXC/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‎‎‎‎‎‏‏‎‏‏‏‏‏‏‎‏‎‏‏‏‎‏‏‎‎‎‏‏‎‏‏‎‏‏‎‎‎‏‎‎‎‏‏‏‎‎‎‎‎‏‎‎‎‎‏‏‎‎‏‎‎‏‏‎<xliff:g id="APP_0">%1$s</xliff:g>‎‏‎‎‏‏‏‎ wants to show ‎‏‎‎‏‏‎<xliff:g id="APP_2">%2$s</xliff:g>‎‏‎‎‏‏‏‎ slices‎‏‎‎‏‎"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‏‏‎‎‎‏‏‏‎‎‎‎‏‎‏‎‏‏‎‏‏‏‎‎‎‏‏‏‎‎‎‏‎‏‎‏‎‏‎‏‏‎‏‏‏‎‎‎‎‏‎‏‎‎‎Allow ‎‏‎‎‏‏‎<xliff:g id="APP_0">%1$s</xliff:g>‎‏‎‎‏‏‏‎ to show ‎‏‎‎‏‏‎<xliff:g id="APP_2">%2$s</xliff:g>‎‏‎‎‏‏‏‎ slices?‎‏‎‎‏‎"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‏‏‎‎‏‏‏‎‏‎‏‎‏‎‏‏‏‏‎‏‏‏‎‎‏‏‎‎‏‏‏‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‏‎‏‏‎- It can read information from ‎‏‎‎‏‏‎<xliff:g id="APP">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‏‎‎‎‏‎‏‎‎‎‏‎‎‎‎‎‏‎‎‏‎‎‏‎‎‏‏‎‏‏‎‎‎‏‏‎‏‎‎‏‏‏‏‎‏‎‏‎‎‏‎‎‏‎‎- It can take actions inside ‎‏‎‎‏‏‎<xliff:g id="APP">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‎‎‎‏‏‏‏‎‏‎‏‏‎‏‏‏‎‎‎‎‏‎‏‏‎‎‎‎‏‏‎‏‏‏‏‎‏‏‎‏‎‏‎‏‏‏‏‏‏‏‏‎‎‏‏‎Allow ‎‏‎‎‏‏‎<xliff:g id="APP">%1$s</xliff:g>‎‏‎‎‏‏‏‎ to show slices from any app‎‏‎‎‏‎"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‏‏‏‎‏‎‏‏‏‏‎‏‏‎‏‏‏‏‎‏‏‎‎‏‎‏‎‎‎‎‏‎‏‏‎‎‎‏‏‎‎‎‏‎‎‏‏‎‏‎‏‏‎‎‎Allow‎‏‎‎‏‎"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‏‎‎‎‎‎‎‎‏‏‎‎‎‎‎‏‏‎‏‎‎‎‏‎‏‎‎‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎‏‎‎‏‎‎‎‎‎‎‏‏‎‎‏‎Deny‎‏‎‎‏‎"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-es-rUS/strings.xml b/slices/core/src/main/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..9db16c5
--- /dev/null
+++ b/slices/core/src/main/res/values-es-rUS/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> quiere mostrar fragmentos de <xliff:g id="APP_2">%2$s</xliff:g>"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"¿Permitir que <xliff:g id="APP_0">%1$s</xliff:g> muestre fragmentos de <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Puede leer información de <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Puede realizar acciones en <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Permitir que <xliff:g id="APP">%1$s</xliff:g> muestre fragmentos de cualquier app"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Permitir"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Rechazar"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-es/strings.xml b/slices/core/src/main/res/values-es/strings.xml
new file mode 100644
index 0000000..690a226
--- /dev/null
+++ b/slices/core/src/main/res/values-es/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> quiere mostrar fragmentos de <xliff:g id="APP_2">%2$s</xliff:g>"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"¿Quieres permitir que <xliff:g id="APP_0">%1$s</xliff:g> muestre fragmentos de <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Puede leer información de <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Puede realizar acciones en <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Permitir que <xliff:g id="APP">%1$s</xliff:g> muestre fragmentos de cualquier aplicación"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Permitir"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Denegar"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-et/strings.xml b/slices/core/src/main/res/values-et/strings.xml
new file mode 100644
index 0000000..6c45d68
--- /dev/null
+++ b/slices/core/src/main/res/values-et/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"Rakendus <xliff:g id="APP_0">%1$s</xliff:g> soovib näidata rakenduse <xliff:g id="APP_2">%2$s</xliff:g> lõike"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Kas lubada rakendusel <xliff:g id="APP_0">%1$s</xliff:g> näidata rakenduse <xliff:g id="APP_2">%2$s</xliff:g> lõike?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- See saab lugeda teavet rakendusest <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- See saab rakenduses <xliff:g id="APP">%1$s</xliff:g> toiminguid teha"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Luba rakendus <xliff:g id="APP">%1$s</xliff:g>, et kuvada lõike mis tahes rakendusest"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Lubamine"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Keelamine"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-eu/strings.xml b/slices/core/src/main/res/values-eu/strings.xml
new file mode 100644
index 0000000..3329fa5
--- /dev/null
+++ b/slices/core/src/main/res/values-eu/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> aplikazioak <xliff:g id="APP_2">%2$s</xliff:g> aplikazioaren zatiak erakutsi nahi ditu"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> aplikazioari <xliff:g id="APP_2">%2$s</xliff:g> aplikazioaren zatiak erakustea baimendu nahi diozu?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- <xliff:g id="APP">%1$s</xliff:g> aplikazioaren informazioa irakur dezake."</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- <xliff:g id="APP">%1$s</xliff:g> aplikazioan ekintzak gauza ditzake."</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Baimendu <xliff:g id="APP">%1$s</xliff:g> aplikazioari edozein aplikazioren zatiak erakustea"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Baimendu"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Ukatu"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-fa/strings.xml b/slices/core/src/main/res/values-fa/strings.xml
new file mode 100644
index 0000000..7ee7fab
--- /dev/null
+++ b/slices/core/src/main/res/values-fa/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> می‌خواهد تکه‌های <xliff:g id="APP_2">%2$s</xliff:g> را نشان دهد"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"به <xliff:g id="APP_0">%1$s</xliff:g> اجازه داده شود تکه‌های <xliff:g id="APP_2">%2$s</xliff:g> را نشان دهد؟"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- می‌تواند اطلاعات <xliff:g id="APP">%1$s</xliff:g> را بخواند"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- می‌تواند در <xliff:g id="APP">%1$s</xliff:g> اقدام انجام دهد"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"به <xliff:g id="APP">%1$s</xliff:g> اجازه داده شود تکه‌هایی از برنامه‌ها نشان دهد"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"مجاز"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"رد کردن"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-fi/strings.xml b/slices/core/src/main/res/values-fi/strings.xml
new file mode 100644
index 0000000..1cc8122
--- /dev/null
+++ b/slices/core/src/main/res/values-fi/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> haluaa näyttää osia sovelluksesta <xliff:g id="APP_2">%2$s</xliff:g>."</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Saako <xliff:g id="APP_0">%1$s</xliff:g> näyttää osia sovelluksesta <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– Se voi lukea tietoja sovelluksesta <xliff:g id="APP">%1$s</xliff:g>."</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– Se voi suorittaa toimintoja sovelluksessa <xliff:g id="APP">%1$s</xliff:g>."</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Salli sovelluksen <xliff:g id="APP">%1$s</xliff:g> näyttää osia mistä tahansa sovelluksesta"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Salli"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Estä"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-fr-rCA/strings.xml b/slices/core/src/main/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..d92e649
--- /dev/null
+++ b/slices/core/src/main/res/values-fr-rCA/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> souhaite afficher <xliff:g id="APP_2">%2$s</xliff:g> tranches"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Autoriser <xliff:g id="APP_0">%1$s</xliff:g> à afficher <xliff:g id="APP_2">%2$s</xliff:g> tranches?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Il peut lire de l\'information de <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Il peut effectuer des actions dans <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Autoriser <xliff:g id="APP">%1$s</xliff:g> à afficher des tranches de n\'importe quelle application"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Autoriser"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Refuser"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-fr/strings.xml b/slices/core/src/main/res/values-fr/strings.xml
new file mode 100644
index 0000000..9edcb27
--- /dev/null
+++ b/slices/core/src/main/res/values-fr/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> souhaite afficher des éléments de <xliff:g id="APP_2">%2$s</xliff:g>"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Autoriser <xliff:g id="APP_0">%1$s</xliff:g> à afficher des éléments de <xliff:g id="APP_2">%2$s</xliff:g> ?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Accès aux informations de <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Capacité d\'action dans <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Autoriser <xliff:g id="APP">%1$s</xliff:g> à afficher des éléments de n\'importe quelle application"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Autoriser"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Refuser"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-gl/strings.xml b/slices/core/src/main/res/values-gl/strings.xml
new file mode 100644
index 0000000..ff9565e
--- /dev/null
+++ b/slices/core/src/main/res/values-gl/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"A aplicación <xliff:g id="APP_0">%1$s</xliff:g> quere mostrar partes de <xliff:g id="APP_2">%2$s</xliff:g>"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Queres permitir que a aplicación <xliff:g id="APP_0">%1$s</xliff:g> mostre partes de <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Pode ler información da aplicación <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Pode levar a cabo accións dentro da aplicación <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Permitir que a aplicación <xliff:g id="APP">%1$s</xliff:g> mostre partes de calquera aplicación"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Permitir"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Denegar"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-gu/strings.xml b/slices/core/src/main/res/values-gu/strings.xml
new file mode 100644
index 0000000..4e8fcb8
--- /dev/null
+++ b/slices/core/src/main/res/values-gu/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> <xliff:g id="APP_2">%2$s</xliff:g> સ્લાઇસ બતાવવા માગે છે"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g>ને <xliff:g id="APP_2">%2$s</xliff:g> સ્લાઇસ બતાવવાની મંજૂરી આપીએ?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- તે <xliff:g id="APP">%1$s</xliff:g>માંથી માહિતી વાંચી શકે છે"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- તે <xliff:g id="APP">%1$s</xliff:g>ની અંદર ક્રિયાઓ કરી શકે છે"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"<xliff:g id="APP">%1$s</xliff:g>ને કોઈપણ ઍપના સ્લાઇસ બતાવવાની મંજૂરી આપો"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"મંજૂરી આપો"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"નકારો"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-hi/strings.xml b/slices/core/src/main/res/values-hi/strings.xml
new file mode 100644
index 0000000..a8e98b9
--- /dev/null
+++ b/slices/core/src/main/res/values-hi/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g>, <xliff:g id="APP_2">%2$s</xliff:g> के हिस्से (स्लाइस) दिखाना चाहता है"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> को <xliff:g id="APP_2">%2$s</xliff:g> के हिस्से (स्लाइस) दिखाने की मंज़ूरी दें?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- यह <xliff:g id="APP">%1$s</xliff:g> से जानकारी पा सकता है"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- यह <xliff:g id="APP">%1$s</xliff:g> में कार्रवाई कर सकता है"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"<xliff:g id="APP">%1$s</xliff:g> काे किसी भी एेप्लिकेशन के हिस्से (स्लाइस) दिखाने की मंज़ूरी दें"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"अनुमति दें"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"नामंज़ूर करें"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-hr/strings.xml b/slices/core/src/main/res/values-hr/strings.xml
new file mode 100644
index 0000000..e0bffaa
--- /dev/null
+++ b/slices/core/src/main/res/values-hr/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> želi prikazivati isječke aplikacije <xliff:g id="APP_2">%2$s</xliff:g>"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Želite li dopustiti aplikaciji <xliff:g id="APP_0">%1$s</xliff:g> da prikazuje isječke aplikacije <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– može čitati informacije aplikacije <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– može vršiti radnje u aplikaciji <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Dopusti aplikaciji <xliff:g id="APP">%1$s</xliff:g> da prikazuje isječke iz bilo koje aplikacije"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Dopusti"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Odbij"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-hu/strings.xml b/slices/core/src/main/res/values-hu/strings.xml
new file mode 100644
index 0000000..4601a88
--- /dev/null
+++ b/slices/core/src/main/res/values-hu/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"A(z) <xliff:g id="APP_0">%1$s</xliff:g> alkalmazás részleteket szeretne megjeleníteni a(z) <xliff:g id="APP_2">%2$s</xliff:g> alkalmazásból"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Engedélyezi a(z) <xliff:g id="APP_0">%1$s</xliff:g> alkalmazásnak, hogy részleteket mutasson a(z) <xliff:g id="APP_2">%2$s</xliff:g> alkalmazásból?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– Információkat olvashat a(z) <xliff:g id="APP">%1$s</xliff:g> alkalmazásból"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– Műveleteket végezhet a(z) <xliff:g id="APP">%1$s</xliff:g> alkalmazáson belül"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Engedélyezi a(z) <xliff:g id="APP">%1$s</xliff:g> alkalmazásnak, hogy bármely alkalmazásból részletet jelenítsen meg"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Engedélyezés"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Elutasítás"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-hy/strings.xml b/slices/core/src/main/res/values-hy/strings.xml
new file mode 100644
index 0000000..c8850ff
--- /dev/null
+++ b/slices/core/src/main/res/values-hy/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> հավելվածն ուզում է ցուցադրել հատվածներ <xliff:g id="APP_2">%2$s</xliff:g> հավելվածից"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Թույլատրե՞լ <xliff:g id="APP_0">%1$s</xliff:g> հավելվածին ցուցադրել հատվածներ <xliff:g id="APP_2">%2$s</xliff:g> հավելվածից"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– Կարող է կարդալ տեղեկություններ <xliff:g id="APP">%1$s</xliff:g> հավելվածից"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– Կարող է կատարել գործողություններ <xliff:g id="APP">%1$s</xliff:g> հավելվածում"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Թույլատրել <xliff:g id="APP">%1$s</xliff:g> հավելվածին ցուցադրել հատվածներ ցանկացած հավելվածից"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Թույլատրել"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Մերժել"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-in/strings.xml b/slices/core/src/main/res/values-in/strings.xml
new file mode 100644
index 0000000..a68a7c7
--- /dev/null
+++ b/slices/core/src/main/res/values-in/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> ingin menampilkan potongan <xliff:g id="APP_2">%2$s</xliff:g>"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Izinkan <xliff:g id="APP_0">%1$s</xliff:g> menampilkan potongan <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Dapat membaca informasi dari <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Dapat mengambil tindakan di dalam <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Izinkan <xliff:g id="APP">%1$s</xliff:g> menampilkan potongan dari aplikasi apa pun"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Izinkan"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Tolak"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-is/strings.xml b/slices/core/src/main/res/values-is/strings.xml
new file mode 100644
index 0000000..24f3ace
--- /dev/null
+++ b/slices/core/src/main/res/values-is/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> vill sýna sneiðar úr <xliff:g id="APP_2">%2$s</xliff:g>"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Viltu leyfa <xliff:g id="APP_0">%1$s</xliff:g> að sýna sneiðar úr <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Það getur lesið upplýsingar úr <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Það getur gripið til aðgerða í <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Leyfa <xliff:g id="APP">%1$s</xliff:g> að sýna sneiðar úr hvaða forriti sem er"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Leyfa"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Hafna"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-it/strings.xml b/slices/core/src/main/res/values-it/strings.xml
new file mode 100644
index 0000000..57540ce
--- /dev/null
+++ b/slices/core/src/main/res/values-it/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"L\'app <xliff:g id="APP_0">%1$s</xliff:g> vuole mostrare porzioni dell\'app <xliff:g id="APP_2">%2$s</xliff:g>"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Vuoi consentire all\'app <xliff:g id="APP_0">%1$s</xliff:g> di mostrare porzioni dell\'app <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Può leggere informazioni dell\'app <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Può compiere azioni nell\'app <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Consenti all\'app <xliff:g id="APP">%1$s</xliff:g> di mostrare porzioni di qualsiasi app"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Consenti"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Nega"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-iw/strings.xml b/slices/core/src/main/res/values-iw/strings.xml
new file mode 100644
index 0000000..78b02aa
--- /dev/null
+++ b/slices/core/src/main/res/values-iw/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> רוצה להציג חלקים מ-<xliff:g id="APP_2">%2$s</xliff:g>"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"האם לאפשר ל-<xliff:g id="APP_0">%1$s</xliff:g> להציג חלקים מ-<xliff:g id="APP_2">%2$s</xliff:g>?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- תהיה לה אפשרות לקרוא מידע מ-<xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- תהיה לה יכולת לנקוט פעולה בתוך <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"יש לאשר ל-<xliff:g id="APP">%1$s</xliff:g> להראות חלקים מכל אפליציה שהיא"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"יש אישור"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"אני לא מרשה"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-ja/strings.xml b/slices/core/src/main/res/values-ja/strings.xml
new file mode 100644
index 0000000..a04df0b
--- /dev/null
+++ b/slices/core/src/main/res/values-ja/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> が <xliff:g id="APP_2">%2$s</xliff:g> のスライスの表示をリクエストしています"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_2">%2$s</xliff:g> のスライスの表示を <xliff:g id="APP_0">%1$s</xliff:g> に許可しますか?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- <xliff:g id="APP">%1$s</xliff:g> からの情報を読み取ることがあります"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- <xliff:g id="APP">%1$s</xliff:g> 内部で操作することがあります"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"すべてのアプリのスライスを表示することを <xliff:g id="APP">%1$s</xliff:g> に許可する"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"許可"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"拒否"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-ka/strings.xml b/slices/core/src/main/res/values-ka/strings.xml
new file mode 100644
index 0000000..f21d1be
--- /dev/null
+++ b/slices/core/src/main/res/values-ka/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g>-ს სურს, გაჩვენოთ <xliff:g id="APP_2">%2$s</xliff:g>-ის ფრაგმენტები"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"ანიჭებთ ნებართვას <xliff:g id="APP_0">%1$s</xliff:g>-ს, აჩვენოს <xliff:g id="APP_2">%2$s</xliff:g>-ის ფრაგმენტები?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- მას შეუძლია ინფორმაციის <xliff:g id="APP">%1$s</xliff:g>-დან წაკითხვა"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- მას შეუძლია ქმედებების <xliff:g id="APP">%1$s</xliff:g>-ში განხორციელება"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"<xliff:g id="APP">%1$s</xliff:g>-ისთვის ფრაგმენტების ნებისმიერი აპიდან ჩვენების ნების დართვა"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"დაშვება"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"უარყოფა"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-kk/strings.xml b/slices/core/src/main/res/values-kk/strings.xml
new file mode 100644
index 0000000..aa9409f
--- /dev/null
+++ b/slices/core/src/main/res/values-kk/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> қолданбасы <xliff:g id="APP_2">%2$s</xliff:g> қолданбасының үзінділерін көрсеткісі келеді"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> қолданбасына <xliff:g id="APP_2">%2$s</xliff:g> қолданбасының үзінділерін көрсетуге рұқсат берілсін бе?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- <xliff:g id="APP">%1$s</xliff:g> қолданбасындағы ақпаратты оқи алады"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- <xliff:g id="APP">%1$s</xliff:g> қолданбасында әрекет ете алады"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"<xliff:g id="APP">%1$s</xliff:g> қолданбасына кез келген қолданбаның үзіндісін көрсетуге рұқсат беру"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Рұқсат беру"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Тыйым салу"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-km/strings.xml b/slices/core/src/main/res/values-km/strings.xml
new file mode 100644
index 0000000..a98f409
--- /dev/null
+++ b/slices/core/src/main/res/values-km/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> ចង់​បង្ហាញ​ស្ថិតិ​ប្រើប្រាស់​របស់ <xliff:g id="APP_2">%2$s</xliff:g>"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"អនុញ្ញាតឱ្យ <xliff:g id="APP_0">%1$s</xliff:g> បង្ហាញ​ស្ថិតិប្រើប្រាស់​របស់ <xliff:g id="APP_2">%2$s</xliff:g> ?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- វា​អាច​អាន​ព័ត៌មាន​ពី <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- វាអាច​ធ្វើសកម្មភាព​នៅក្នុង <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"អនុញ្ញាត​ឱ្យ <xliff:g id="APP">%1$s</xliff:g> បង្ហាញ​ស្ថិតិ​ប្រើប្រាស់​ពី​កម្មវិធី​នានា"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"អនុញ្ញាត"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"បដិសេធ"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-kn/strings.xml b/slices/core/src/main/res/values-kn/strings.xml
new file mode 100644
index 0000000..e8a0559
--- /dev/null
+++ b/slices/core/src/main/res/values-kn/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_2">%2$s</xliff:g> ಸ್ಲೈಸ್‌ಗಳನ್ನು <xliff:g id="APP_0">%1$s</xliff:g> ತೋರಿಸಲು ಬಯಸಿದೆ"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_2">%2$s</xliff:g> ಸ್ಲೈಸ್‌ಗಳನ್ನು ತೋರಿಸಲು <xliff:g id="APP_0">%1$s</xliff:g> ಅನ್ನು ಅನುಮತಿಸುವುದೇ?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- ಇದು <xliff:g id="APP">%1$s</xliff:g> ನಿಂದ ಮಾಹಿತಿಯನ್ನು ಓದಬಹುದು"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- ಇದು <xliff:g id="APP">%1$s</xliff:g> ಒಳಗಡೆ ಕ್ರಿಯೆಗಳನ್ನು ತೆಗೆದುಕೊಳ್ಳಬಹುದು"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"ಯಾವುದೇ ಅಪ್ಲಿಕೇಶನ್‌ನಿಂದ ಸ್ಲೈಸ್‌ಗಳನ್ನು ತೋರಿಸಲು <xliff:g id="APP">%1$s</xliff:g> ಅನ್ನು ಅನುಮತಿಸಿ"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"ಅನುಮತಿಸಿ"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"ನಿರಾಕರಿಸಿ"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-ko/strings.xml b/slices/core/src/main/res/values-ko/strings.xml
new file mode 100644
index 0000000..cc88f25
--- /dev/null
+++ b/slices/core/src/main/res/values-ko/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g>에서 <xliff:g id="APP_2">%2$s</xliff:g>의 슬라이스를 표시하려고 합니다."</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g>에서 <xliff:g id="APP_2">%2$s</xliff:g>의 슬라이스를 표시하도록 허용하시겠습니까?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- <xliff:g id="APP">%1$s</xliff:g>의 정보를 읽을 수 있음"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- <xliff:g id="APP">%1$s</xliff:g>에서 작업할 수 있음"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"<xliff:g id="APP">%1$s</xliff:g>에서 모든 앱의 슬라이스를 표시하도록 허용"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"허용"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"거부"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-ky/strings.xml b/slices/core/src/main/res/values-ky/strings.xml
new file mode 100644
index 0000000..f2edce4
--- /dev/null
+++ b/slices/core/src/main/res/values-ky/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> колдонмосу <xliff:g id="APP_2">%2$s</xliff:g> үлгүлөрүн көрсөткөнү жатат"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> колдонмосуна <xliff:g id="APP_2">%2$s</xliff:g> үлгүлөрүн көрсөтүүгө уруксат берилсинби?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- <xliff:g id="APP">%1$s</xliff:g> колдонмосунун маалыматын окуйт"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- <xliff:g id="APP">%1$s</xliff:g> колдонмосунда аракеттерди аткарат"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"<xliff:g id="APP">%1$s</xliff:g> бардык колдонмолордун үлгүлөрүн көрсөтүүгө уруксат берүү"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Уруксат берүү"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Жок"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-lo/strings.xml b/slices/core/src/main/res/values-lo/strings.xml
new file mode 100644
index 0000000..74bb119
--- /dev/null
+++ b/slices/core/src/main/res/values-lo/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> ຕ້ອງການສະແດງ <xliff:g id="APP_2">%2$s</xliff:g> ສະໄລ້"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"ອະນຸຍາດ <xliff:g id="APP_0">%1$s</xliff:g> ໃຫ້ສະແດງ <xliff:g id="APP_2">%2$s</xliff:g> ສະໄລ້ບໍ?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- ມັນສາມາດອ່ານຂໍ້ມູນຈາກ <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- ມັນສາມາດໃຊ້ຄຳສັ່ງພາຍໃນ <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"ອະນຸຍາດ <xliff:g id="APP">%1$s</xliff:g> ເພື່ອສະແດງສະໄລ້ຈາກແອັບ"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"ອະນຸຍາດ"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"ປະຕິເສດ"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-lt/strings.xml b/slices/core/src/main/res/values-lt/strings.xml
new file mode 100644
index 0000000..50eb4a6
--- /dev/null
+++ b/slices/core/src/main/res/values-lt/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"„<xliff:g id="APP_0">%1$s</xliff:g>“ nori rodyti „<xliff:g id="APP_2">%2$s</xliff:g>“ fragmentus"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Leisti „<xliff:g id="APP_0">%1$s</xliff:g>“ rodyti „<xliff:g id="APP_2">%2$s</xliff:g>“ fragmentus?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– Gali nuskaityti informaciją iš „<xliff:g id="APP">%1$s</xliff:g>“"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– Gali imtis veiksmų programoje „<xliff:g id="APP">%1$s</xliff:g>“"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Leisti „<xliff:g id="APP">%1$s</xliff:g>“ rodyti bet kurios programos fragmentus"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Leisti"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Atmesti"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-lv/strings.xml b/slices/core/src/main/res/values-lv/strings.xml
new file mode 100644
index 0000000..4bfb688
--- /dev/null
+++ b/slices/core/src/main/res/values-lv/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"Lietotne <xliff:g id="APP_0">%1$s</xliff:g> vēlas rādīt lietotnes <xliff:g id="APP_2">%2$s</xliff:g> sadaļas"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Vai atļaut lietotnei <xliff:g id="APP_0">%1$s</xliff:g> rādīt lietotnes <xliff:g id="APP_2">%2$s</xliff:g> sadaļas?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Var lasīt informāciju no lietotnes <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Var veikt darbības lietotnē <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Atļaut lietotnei <xliff:g id="APP">%1$s</xliff:g> rādīt sadaļas no jebkuras lietotnes"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Atļaut"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Neatļaut"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-mk/strings.xml b/slices/core/src/main/res/values-mk/strings.xml
new file mode 100644
index 0000000..2525781
--- /dev/null
+++ b/slices/core/src/main/res/values-mk/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> сака да прикажува делови од <xliff:g id="APP_2">%2$s</xliff:g>"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Да се дозволи <xliff:g id="APP_0">%1$s</xliff:g> да прикажува делови од <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Може да чита информации од <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Може да презема дејства во <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Дозволете <xliff:g id="APP">%1$s</xliff:g> да прикажува делови од која било апликација"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Дозволете"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Одбијте"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-ml/strings.xml b/slices/core/src/main/res/values-ml/strings.xml
new file mode 100644
index 0000000..ce177d2
--- /dev/null
+++ b/slices/core/src/main/res/values-ml/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_2">%2$s</xliff:g> സ്ലൈസുകൾ കാണിക്കാൻ <xliff:g id="APP_0">%1$s</xliff:g> താൽപ്പര്യപ്പെടുന്നു"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_2">%2$s</xliff:g> സ്ലൈസുകൾ കാണിക്കാൻ <xliff:g id="APP_0">%1$s</xliff:g>-നെ അനുവദിക്കണോ?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- ഇതിന് <xliff:g id="APP">%1$s</xliff:g>-ൽ നിന്ന് വിവരങ്ങൾ വായിക്കാനാകും"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- ഇതിന് <xliff:g id="APP">%1$s</xliff:g>-നുള്ളിൽ പ്രവർത്തനങ്ങൾ ചെയ്യാനാകും"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"ഏത് ആപ്പിൽ നിന്നും സ്ലൈസുകൾ കാണിക്കാൻ <xliff:g id="APP">%1$s</xliff:g>-നെ അനുവദിക്കുക"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"അനുവദിക്കുക"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"നിരസിക്കുക"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-mn/strings.xml b/slices/core/src/main/res/values-mn/strings.xml
new file mode 100644
index 0000000..50764d9
--- /dev/null
+++ b/slices/core/src/main/res/values-mn/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> <xliff:g id="APP_2">%2$s</xliff:g>-н хэсгүүдийг харуулах хүсэлтэй байна"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g>-д <xliff:g id="APP_2">%2$s</xliff:g>-н хэсгүүдийг харуулахыг зөвшөөрөх үү?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Энэ <xliff:g id="APP">%1$s</xliff:g>-с мэдээлэл унших боломжтой"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Энэ <xliff:g id="APP">%1$s</xliff:g> дотор үйлдэл хийх боломжтой"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"<xliff:g id="APP">%1$s</xliff:g>-д дурын аппаас хэсэг харуулахыг зөвшөөрөх"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Зөвшөөрөх"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Татгалзах"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-mr/strings.xml b/slices/core/src/main/res/values-mr/strings.xml
new file mode 100644
index 0000000..f938652
--- /dev/null
+++ b/slices/core/src/main/res/values-mr/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> ला <xliff:g id="APP_2">%2$s</xliff:g> चे तुकडे दाखवायचे आहेत"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> ला <xliff:g id="APP_2">%2$s</xliff:g> चे तुकडे दाखवण्याची अनुमती द्यायची का?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- ते <xliff:g id="APP">%1$s</xliff:g> ची माहिती वाचू शकते"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- ते <xliff:g id="APP">%1$s</xliff:g> मध्ये कृती करू शकते"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"<xliff:g id="APP">%1$s</xliff:g> ला कुठल्याही अ‍ॅपमधील तुकडे दाखवण्याची अनुमती द्या"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"अनुमती द्या"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"नकार द्या"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-ms/strings.xml b/slices/core/src/main/res/values-ms/strings.xml
new file mode 100644
index 0000000..af2a67e
--- /dev/null
+++ b/slices/core/src/main/res/values-ms/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> mahu menunjukkan hirisan <xliff:g id="APP_2">%2$s</xliff:g>"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Benarkan <xliff:g id="APP_0">%1$s</xliff:g> menunjukkan hirisan <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Hos hirisan boleh membaca maklumat daripada <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Hos hirisan boleh mengambil tindakan dalam <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Benarkan <xliff:g id="APP">%1$s</xliff:g> menunjukkan hirisan daripada mana-mana apl"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Benarkan"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Tolak"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-my/strings.xml b/slices/core/src/main/res/values-my/strings.xml
new file mode 100644
index 0000000..0cf5d3e
--- /dev/null
+++ b/slices/core/src/main/res/values-my/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> သည် <xliff:g id="APP_2">%2$s</xliff:g> ၏အချပ်များကို ပြသလိုသည်"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> အား <xliff:g id="APP_2">%2$s</xliff:g> ၏အချပ်များ ပြသခွင့်ပြုပါသလား။"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- ၎င်းသည် <xliff:g id="APP">%1$s</xliff:g> မှ အချက်အလက်ကို ဖတ်နိုင်သည်"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- ၎င်းသည် <xliff:g id="APP">%1$s</xliff:g> အတွင်း လုပ်ဆောင်ချက်များ ပြုလုပ်နိုင်သည်"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"မည်သည့်အက်ပ်မဆိုမှ အချပ်များ ပြသရန်အတွက် <xliff:g id="APP">%1$s</xliff:g> ကို ခွင့်ပြုရန်"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"ခွင့်ပြုရန်"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"ငြင်းပယ်ရန်"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-nb/strings.xml b/slices/core/src/main/res/values-nb/strings.xml
new file mode 100644
index 0000000..634eac3
--- /dev/null
+++ b/slices/core/src/main/res/values-nb/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> vil vise <xliff:g id="APP_2">%2$s</xliff:g>-utsnitt"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Vil du tillate at <xliff:g id="APP_0">%1$s</xliff:g> viser <xliff:g id="APP_2">%2$s</xliff:g>-utsnitt?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– Den kan lese informasjon fra <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– Den kan utføre handlinger i <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Tillat at <xliff:g id="APP">%1$s</xliff:g> viser utsnitt fra alle apper"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Tillat"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Ikke tillat"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-ne/strings.xml b/slices/core/src/main/res/values-ne/strings.xml
new file mode 100644
index 0000000..c5c9de3
--- /dev/null
+++ b/slices/core/src/main/res/values-ne/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> <xliff:g id="APP_2">%2$s</xliff:g> का स्लाइसहरू देखाउन चाहन्छ"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> लाई <xliff:g id="APP_2">%2$s</xliff:g> का स्लाइसहरू देखाउन अनुमति दिने हो?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- यसले <xliff:g id="APP">%1$s</xliff:g> को जानकारी पढ्न सक्छ"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- यसले <xliff:g id="APP">%1$s</xliff:g> भित्र कारबाही गर्न सक्छ"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"<xliff:g id="APP">%1$s</xliff:g> लाई सबै अनुप्रयोगका स्लाइसहरू देखाउन अनुमति दिनुहोस्"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"अनुमति दिनुहोस्"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"अस्वीकार गर्नु…"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-nl/strings.xml b/slices/core/src/main/res/values-nl/strings.xml
new file mode 100644
index 0000000..a847b8c
--- /dev/null
+++ b/slices/core/src/main/res/values-nl/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> wil segmenten van <xliff:g id="APP_2">%2$s</xliff:g> weergeven"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> toestaan om segmenten van <xliff:g id="APP_2">%2$s</xliff:g> weer te geven?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Deze kan informatie lezen van <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Deze kan acties uitvoeren in <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"<xliff:g id="APP">%1$s</xliff:g> toestaan om segmenten van apps weer te geven"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Toestaan"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Weigeren"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-pa/strings.xml b/slices/core/src/main/res/values-pa/strings.xml
new file mode 100644
index 0000000..e1ef272
--- /dev/null
+++ b/slices/core/src/main/res/values-pa/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> ਦੀ <xliff:g id="APP_2">%2$s</xliff:g> ਦੇ ਹਿੱਸੇ ਦਿਖਾਉਣ ਦੀ ਇੱਛਾ ਹੈ"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"ਕੀ <xliff:g id="APP_0">%1$s</xliff:g> ਨੂੰ <xliff:g id="APP_2">%2$s</xliff:g> ਦੇ ਹਿੱਸੇ ਦਿਖਾਉਣ ਦੇਣੇ ਹਨ?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- ਇਹ <xliff:g id="APP">%1$s</xliff:g> ਵਿੱਚੋਂ ਜਾਣਕਾਰੀ ਪੜ੍ਹ ਸਕਦਾ ਹੈ"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- ਇਸ <xliff:g id="APP">%1$s</xliff:g> ਦੇ ਅੰਦਰ ਕਾਰਵਾਈਆਂ ਕਰ ਸਕਦਾ ਹੈ"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"<xliff:g id="APP">%1$s</xliff:g> ਨੂੰ ਕਿਸੇ ਵੀ ਐਪ ਵਿੱਚੋਂ ਹਿੱਸੇ ਦਿਖਾਉਣ ਦਿਓ"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"ਕਰਨ ਦਿਓ"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"ਅਸਵੀਕਾਰ ਕਰੋ"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-pl/strings.xml b/slices/core/src/main/res/values-pl/strings.xml
new file mode 100644
index 0000000..f66d32c
--- /dev/null
+++ b/slices/core/src/main/res/values-pl/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"Aplikacja <xliff:g id="APP_0">%1$s</xliff:g> chce pokazywać wycinki z aplikacji <xliff:g id="APP_2">%2$s</xliff:g>"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Zezwolić aplikacji <xliff:g id="APP_0">%1$s</xliff:g> na pokazywanie wycinków z aplikacji <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Może odczytywać informacje z aplikacji <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Może wykonywać działania w aplikacji <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Zezwalaj aplikacji <xliff:g id="APP">%1$s</xliff:g> na pokazywanie wycinków z dowolnych aplikacji"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Zezwól"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Odmów"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-pt-rBR/strings.xml b/slices/core/src/main/res/values-pt-rBR/strings.xml
new file mode 100644
index 0000000..246fc77
--- /dev/null
+++ b/slices/core/src/main/res/values-pt-rBR/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> quer mostrar partes do app <xliff:g id="APP_2">%2$s</xliff:g>"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Permitir que <xliff:g id="APP_0">%1$s</xliff:g> mostre partes do app <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Pode ler informações do app <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Pode realizar ações no app <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Permitir que <xliff:g id="APP">%1$s</xliff:g> mostre partes de qualquer app"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Permitir"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Negar"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-pt-rPT/strings.xml b/slices/core/src/main/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..ea2a008
--- /dev/null
+++ b/slices/core/src/main/res/values-pt-rPT/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"A aplicação <xliff:g id="APP_0">%1$s</xliff:g> pretende mostrar partes da aplicação <xliff:g id="APP_2">%2$s</xliff:g>."</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Pretende permitir que a aplicação <xliff:g id="APP_0">%1$s</xliff:g> mostre partes da aplicação <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Pode ler informações da aplicação <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Pode realizar ações na aplicação <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Permitir que a aplicação <xliff:g id="APP">%1$s</xliff:g> mostre partes de qualquer aplicação"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Permitir"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Recusar"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-pt/strings.xml b/slices/core/src/main/res/values-pt/strings.xml
new file mode 100644
index 0000000..246fc77
--- /dev/null
+++ b/slices/core/src/main/res/values-pt/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> quer mostrar partes do app <xliff:g id="APP_2">%2$s</xliff:g>"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Permitir que <xliff:g id="APP_0">%1$s</xliff:g> mostre partes do app <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Pode ler informações do app <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Pode realizar ações no app <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Permitir que <xliff:g id="APP">%1$s</xliff:g> mostre partes de qualquer app"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Permitir"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Negar"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-ro/strings.xml b/slices/core/src/main/res/values-ro/strings.xml
new file mode 100644
index 0000000..f4b1135
--- /dev/null
+++ b/slices/core/src/main/res/values-ro/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> vrea să afișeze porțiuni din <xliff:g id="APP_2">%2$s</xliff:g>"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Permiteți <xliff:g id="APP_0">%1$s</xliff:g> să afișeze porțiuni din <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Poate citi informații din <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Poate efectua acțiuni în <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Permiteți <xliff:g id="APP">%1$s</xliff:g> să afișeze porțiuni din orice aplicație"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Permiteți"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Refuzați"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-ru/strings.xml b/slices/core/src/main/res/values-ru/strings.xml
new file mode 100644
index 0000000..43e261f
--- /dev/null
+++ b/slices/core/src/main/res/values-ru/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"Приложение \"<xliff:g id="APP_0">%1$s</xliff:g>\" запрашивает разрешение на показ фрагментов приложения \"<xliff:g id="APP_2">%2$s</xliff:g>\"."</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Разрешить приложению \"<xliff:g id="APP_0">%1$s</xliff:g>\" показывать фрагменты приложения \"<xliff:g id="APP_2">%2$s</xliff:g>\"?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– Ему станут доступны данные из приложения \"<xliff:g id="APP">%1$s</xliff:g>\"."</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– Оно сможет совершать действия в приложении \"<xliff:g id="APP">%1$s</xliff:g>\"."</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Разрешить приложению \"<xliff:g id="APP">%1$s</xliff:g>\" показывать фрагменты других приложений"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Да"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Нет"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-si/strings.xml b/slices/core/src/main/res/values-si/strings.xml
new file mode 100644
index 0000000..70816e1
--- /dev/null
+++ b/slices/core/src/main/res/values-si/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> හට කොටස් <xliff:g id="APP_2">%2$s</xliff:g>ක් පෙන්වීමට අවශ්‍යයි"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> හට කොටස් <xliff:g id="APP_2">%2$s</xliff:g>ක් පෙන්වීමට ඉඩ දෙන්නද?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- එයට <xliff:g id="APP">%1$s</xliff:g> වෙතින් තොරතුරු කියවිය හැකිය"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- එයට <xliff:g id="APP">%1$s</xliff:g> ඇතුළත ක්‍රියාමාර්ග ගත හැකිය"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"ඕනෑම යෙදුමකින් කොටස් පෙන්වීමට <xliff:g id="APP">%1$s</xliff:g> හට ඉඩ දෙන්න"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"ඉඩ දෙන්න"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"ප්‍රතික්ෂේප කර."</string>
+</resources>
diff --git a/slices/core/src/main/res/values-sk/strings.xml b/slices/core/src/main/res/values-sk/strings.xml
new file mode 100644
index 0000000..4937a6c
--- /dev/null
+++ b/slices/core/src/main/res/values-sk/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> chce zobrazovať rezy z aplikácie <xliff:g id="APP_2">%2$s</xliff:g>"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Povoliť aplikácii <xliff:g id="APP_0">%1$s</xliff:g> zobrazovať rezy z aplikácie <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– Môže čítať informácie z aplikácie <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– Môže vykonávať akcie v aplikácii <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Povoliť aplikácii <xliff:g id="APP">%1$s</xliff:g> zobrazovať rezy z ľubovoľnej aplikácie"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Povoliť"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Zamietnuť"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-sl/strings.xml b/slices/core/src/main/res/values-sl/strings.xml
new file mode 100644
index 0000000..30f67c4
--- /dev/null
+++ b/slices/core/src/main/res/values-sl/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"Aplikacija <xliff:g id="APP_0">%1$s</xliff:g> želi prikazati izreze iz aplikacije <xliff:g id="APP_2">%2$s</xliff:g>"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Ali aplikaciji <xliff:g id="APP_0">%1$s</xliff:g> dovolite prikazovanje izrezov iz aplikacije <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– lahko bere podatke v aplikaciji <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– lahko izvaja dejanja v aplikaciji <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Dovoli, da aplikacija <xliff:g id="APP">%1$s</xliff:g> prikaže izreze iz poljubne aplikacije"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Dovoli"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Zavrni"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-sq/strings.xml b/slices/core/src/main/res/values-sq/strings.xml
new file mode 100644
index 0000000..47ce934
--- /dev/null
+++ b/slices/core/src/main/res/values-sq/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> dëshiron të shfaqë pjesë të <xliff:g id="APP_2">%2$s</xliff:g>"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Të lejohet <xliff:g id="APP_0">%1$s</xliff:g> që të shfaqë pjesë të <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Mund të lexojë informacion nga <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Mund të ndërmarrë veprime brenda <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Lejo <xliff:g id="APP">%1$s</xliff:g> për të shfaqur pjesë nga çdo aplikacion"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Lejo"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Refuzo"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-sr/strings.xml b/slices/core/src/main/res/values-sr/strings.xml
new file mode 100644
index 0000000..e059b1c
--- /dev/null
+++ b/slices/core/src/main/res/values-sr/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"Апликација <xliff:g id="APP_0">%1$s</xliff:g> жели да приказује исечке из апликације <xliff:g id="APP_2">%2$s</xliff:g>"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Желите ли да дозволите апликацији <xliff:g id="APP_0">%1$s</xliff:g> да приказује исечке из апликације <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– Може да чита податке из апликације <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– Може да обавља радње у апликацији <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Дозволи апликацији <xliff:g id="APP">%1$s</xliff:g> да приказује исечке из било које апликације"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Дозволи"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Одбиј"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-sv/strings.xml b/slices/core/src/main/res/values-sv/strings.xml
new file mode 100644
index 0000000..e065cb3
--- /dev/null
+++ b/slices/core/src/main/res/values-sv/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> vill kunna visa bitar av <xliff:g id="APP_2">%2$s</xliff:g>"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Tillåter du att bitar av <xliff:g id="APP_2">%2$s</xliff:g> visas i <xliff:g id="APP_0">%1$s</xliff:g>?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– Kan läsa information från <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– Kan vidta åtgärder i <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Tillåt att bitar av vilken app som helst visas i <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Tillåt"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Neka"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-sw/strings.xml b/slices/core/src/main/res/values-sw/strings.xml
new file mode 100644
index 0000000..2365547
--- /dev/null
+++ b/slices/core/src/main/res/values-sw/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> inataka kuonyesha vipengee <xliff:g id="APP_2">%2$s</xliff:g>"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Ungependa kuruhusu <xliff:g id="APP_0">%1$s</xliff:g> ionyeshe vipengee <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Inaweza kusoma maelezo kutoka <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Inaweza kuchukua hatua ndani ya <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Ruhusu <xliff:g id="APP">%1$s</xliff:g> ionyeshe vipengee kutoka programu yoyote"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Ruhusu"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Kataa"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-ta/strings.xml b/slices/core/src/main/res/values-ta/strings.xml
new file mode 100644
index 0000000..8ab82bd
--- /dev/null
+++ b/slices/core/src/main/res/values-ta/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_2">%2$s</xliff:g> பயன்பாட்டின் விழிப்பூட்டல்களைக் காண்பிக்க, <xliff:g id="APP_0">%1$s</xliff:g> அனுமதி கேட்கிறது"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_2">%2$s</xliff:g> பயன்பாட்டின் விழிப்பூட்டல்களைக் காண்பிக்க, <xliff:g id="APP_0">%1$s</xliff:g> பயன்பாட்டை அனுமதிக்கவா?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- இது, <xliff:g id="APP">%1$s</xliff:g> பயன்பாட்டிலிருக்கும் தகவலைப் படிக்கும்"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- இது, <xliff:g id="APP">%1$s</xliff:g> பயன்பாட்டிற்குள் செயல்பாடுகளில் ஈடுபடும்"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"எந்தப் பயன்பாட்டிலிருந்தும் விழிப்பூட்டல்களைக் காண்பிக்க, <xliff:g id="APP">%1$s</xliff:g> பயன்பாட்டை அனுமதி"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"அனுமதி"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"நிராகரி"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-te/strings.xml b/slices/core/src/main/res/values-te/strings.xml
new file mode 100644
index 0000000..3f89a75
--- /dev/null
+++ b/slices/core/src/main/res/values-te/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> <xliff:g id="APP_2">%2$s</xliff:g> స్లైస్‌లను చూపించాలనుకుంటోంది"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_2">%2$s</xliff:g> స్లైస్‌లను చూపించడానికి <xliff:g id="APP_0">%1$s</xliff:g>ని అనుమతించాలా?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- ఇది <xliff:g id="APP">%1$s</xliff:g> నుండి సమాచారాన్ని చదవగలుగుతుంది"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- ఇది <xliff:g id="APP">%1$s</xliff:g> లోపల చర్యలు తీసుకోగలుగుతుంది"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"ఏ యాప్ నుండి అయినా స్లైస్‌లను చూపించడానికి <xliff:g id="APP">%1$s</xliff:g>ని అనుమతించండి"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"అనుమతించు"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"తిరస్కరించు"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-th/strings.xml b/slices/core/src/main/res/values-th/strings.xml
new file mode 100644
index 0000000..afc42f2
--- /dev/null
+++ b/slices/core/src/main/res/values-th/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> ต้องการแสดงส่วนต่างๆ ของ <xliff:g id="APP_2">%2$s</xliff:g>"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"อนุญาตให้ <xliff:g id="APP_0">%1$s</xliff:g> แสดงส่วนต่างๆ ของ <xliff:g id="APP_2">%2$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- อ่านข้อมูลจาก <xliff:g id="APP">%1$s</xliff:g> ได้"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- ดำเนินการใน <xliff:g id="APP">%1$s</xliff:g> ได้"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"อนุญาตให้ <xliff:g id="APP">%1$s</xliff:g> แสดงส่วนต่างๆ จากแอปใดก็ได้"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"อนุญาต"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"ปฏิเสธ"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-tl/strings.xml b/slices/core/src/main/res/values-tl/strings.xml
new file mode 100644
index 0000000..aa9d7b4
--- /dev/null
+++ b/slices/core/src/main/res/values-tl/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"Gustong ipakita ng <xliff:g id="APP_0">%1$s</xliff:g> ang mga slice ng <xliff:g id="APP_2">%2$s</xliff:g>"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Payagan ang <xliff:g id="APP_0">%1$s</xliff:g> na ipakita ang mga slice ng <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Nakakabasa ito ng impormasyon mula sa <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Nakakagawa ito ng mga pagkilos sa loob ng <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Payagan ang <xliff:g id="APP">%1$s</xliff:g> na ipakita ang mga slice mula sa anumang app"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Payagan"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Tanggihan"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-tr/strings.xml b/slices/core/src/main/res/values-tr/strings.xml
new file mode 100644
index 0000000..216a87c
--- /dev/null
+++ b/slices/core/src/main/res/values-tr/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> uygulaması, <xliff:g id="APP_2">%2$s</xliff:g> dilimlerini göstermek istiyor"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> uygulamasının, <xliff:g id="APP_2">%2$s</xliff:g> dilimlerini göstermesine izin verilsin mi?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- <xliff:g id="APP">%1$s</xliff:g> uygulamasından bilgileri okuyabilir"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- <xliff:g id="APP">%1$s</xliff:g> uygulamasında işlem yapabilir"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"<xliff:g id="APP">%1$s</xliff:g> uygulamasının tüm uygulamalardan dilimleri göstermesine izin ver"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"İzin ver"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Reddet"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-uk/strings.xml b/slices/core/src/main/res/values-uk/strings.xml
new file mode 100644
index 0000000..e908f43
--- /dev/null
+++ b/slices/core/src/main/res/values-uk/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> хоче показати фрагменти додатка <xliff:g id="APP_2">%2$s</xliff:g>"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Дозволити додатку <xliff:g id="APP_0">%1$s</xliff:g> показувати фрагменти додатка <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Може переглядати інформацію з додатка <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Може виконувати дії в додатку <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Дозволити додатку <xliff:g id="APP">%1$s</xliff:g> показувати фрагменти будь-якого додатка"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Дозволити"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Заборонити"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-ur/strings.xml b/slices/core/src/main/res/values-ur/strings.xml
new file mode 100644
index 0000000..0e97e52
--- /dev/null
+++ b/slices/core/src/main/res/values-ur/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> <xliff:g id="APP_2">%2$s</xliff:g> کے سلائسز دکھانا چاہتی ہے"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> کو <xliff:g id="APP_2">%2$s</xliff:g> کے سلائسز دکھانے کی اجازت دیں؟"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- یہ <xliff:g id="APP">%1$s</xliff:g> کی معلومات پڑھ سکتا ہے"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- یہ <xliff:g id="APP">%1$s</xliff:g> کے اندر کارروائیاں کر سکتا ہے"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"<xliff:g id="APP">%1$s</xliff:g> کو کسی بھی ایپ سے سلائسز دکھانے کی اجازت دیں"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"اجازت دیں"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"مسترد کریں"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-uz/strings.xml b/slices/core/src/main/res/values-uz/strings.xml
new file mode 100644
index 0000000..8de5b2e
--- /dev/null
+++ b/slices/core/src/main/res/values-uz/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> ilovasi <xliff:g id="APP_2">%2$s</xliff:g> ilovasidan fragmentlar ko‘rsatish uchun ruxsat so‘ramoqda"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> ilovasiga <xliff:g id="APP_2">%2$s</xliff:g> ilovasidan fragmentlar ko‘rsatishga ruxsat berilsinmi?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– <xliff:g id="APP">%1$s</xliff:g> ma’lumotlarini o‘qiy oladi"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– <xliff:g id="APP">%1$s</xliff:g> ichida amallar bajara oladi"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"<xliff:g id="APP">%1$s</xliff:g> ilovasiga boshqa ilovalardan fragmentlarni ko‘rsatishga ruxsat berish"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Ruxsat"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Rad etish"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-vi/strings.xml b/slices/core/src/main/res/values-vi/strings.xml
new file mode 100644
index 0000000..8ecd246
--- /dev/null
+++ b/slices/core/src/main/res/values-vi/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> muốn hiển thị các lát của <xliff:g id="APP_2">%2$s</xliff:g>"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Cho phép <xliff:g id="APP_0">%1$s</xliff:g> hiển thị các lát của <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Có thể đọc thông tin từ <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Có thể thực hiện hành động bên trong <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Cho phép <xliff:g id="APP">%1$s</xliff:g> hiển thị các lát từ mọi ứng dụng"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Cho phép"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Từ chối"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-zh-rCN/strings.xml b/slices/core/src/main/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..3a99e82
--- /dev/null
+++ b/slices/core/src/main/res/values-zh-rCN/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"“<xliff:g id="APP_0">%1$s</xliff:g>”想要显示“<xliff:g id="APP_2">%2$s</xliff:g>”图块"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"要允许“<xliff:g id="APP_0">%1$s</xliff:g>”显示“<xliff:g id="APP_2">%2$s</xliff:g>”图块吗?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- 可以读取“<xliff:g id="APP">%1$s</xliff:g>”中的信息"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- 可以在“<xliff:g id="APP">%1$s</xliff:g>”内执行操作"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"允许“<xliff:g id="APP">%1$s</xliff:g>”显示任何应用的图块"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"允许"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"拒绝"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-zh-rHK/strings.xml b/slices/core/src/main/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..bb478fc
--- /dev/null
+++ b/slices/core/src/main/res/values-zh-rHK/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"「<xliff:g id="APP_0">%1$s</xliff:g>」想顯示「<xliff:g id="APP_2">%2$s</xliff:g>」的快訊"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"要允許「<xliff:g id="APP_0">%1$s</xliff:g>」顯示「<xliff:g id="APP_2">%2$s</xliff:g>」的快訊嗎?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- 可以讀取「<xliff:g id="APP">%1$s</xliff:g>」中的資料"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- 可以在「<xliff:g id="APP">%1$s</xliff:g>」內執行操作"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"允許「<xliff:g id="APP">%1$s</xliff:g>」顯示任何應用程式的快訊"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"允許"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"拒絕"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-zh-rTW/strings.xml b/slices/core/src/main/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..caeeff1
--- /dev/null
+++ b/slices/core/src/main/res/values-zh-rTW/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"「<xliff:g id="APP_0">%1$s</xliff:g>」想要顯示「<xliff:g id="APP_2">%2$s</xliff:g>」的區塊"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"要允許「<xliff:g id="APP_0">%1$s</xliff:g>」顯示「<xliff:g id="APP_2">%2$s</xliff:g>」的區塊嗎?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- 它可以讀取「<xliff:g id="APP">%1$s</xliff:g>」的資訊"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- 它可以在「<xliff:g id="APP">%1$s</xliff:g>」內執行操作"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"允許「<xliff:g id="APP">%1$s</xliff:g>」顯示任何應用程式的區塊"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"允許"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"拒絕"</string>
+</resources>
diff --git a/slices/core/src/main/res/values-zu/strings.xml b/slices/core/src/main/res/values-zu/strings.xml
new file mode 100644
index 0000000..940334c
--- /dev/null
+++ b/slices/core/src/main/res/values-zu/strings.xml
@@ -0,0 +1,27 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"I-<xliff:g id="APP_0">%1$s</xliff:g> ifuna ukubonisa izingcezu ze-<xliff:g id="APP_2">%2$s</xliff:g>"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"Vumela i-<xliff:g id="APP_0">%1$s</xliff:g> ukuthi ibonise izingcezu ze-<xliff:g id="APP_2">%2$s</xliff:g>?"</string>
+    <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Ingafunda ulwazi kusukela ku-<xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Ingenza izenzo ngaphakathi kwe-<xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Vumela i-<xliff:g id="APP">%1$s</xliff:g> ukuthi ikubonise izingcezu kusukela kunoma iluphi uhlelo lokusebenza"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Vumela"</string>
+    <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Phika"</string>
+</resources>
diff --git a/slices/view/api/current.txt b/slices/view/api/current.txt
index d158818..f201238 100644
--- a/slices/view/api/current.txt
+++ b/slices/view/api/current.txt
@@ -4,6 +4,7 @@
     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 android.net.Uri mapIntentToUri(android.content.Intent);
     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);
@@ -17,6 +18,7 @@
 
   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
@@ -75,11 +77,13 @@
     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
diff --git a/slices/view/build.gradle b/slices/view/build.gradle
index 93e9fc5..0d9d277 100644
--- a/slices/view/build.gradle
+++ b/slices/view/build.gradle
@@ -41,7 +41,7 @@
     name = "Slice views"
     publish = true
     mavenVersion = LibraryVersions.SUPPORT_LIBRARY
-    mavenGroup = LibraryGroups.SLICES
+    mavenGroup = LibraryGroups.SUPPORT
     inceptionYear = "2017"
     description = "A library that handles rendering of slice content into supported templates"
     minSdkVersion = 24
diff --git a/slices/view/src/androidTest/AndroidManifest.xml b/slices/view/src/androidTest/AndroidManifest.xml
index ec64cc1..e98f69d 100644
--- a/slices/view/src/androidTest/AndroidManifest.xml
+++ b/slices/view/src/androidTest/AndroidManifest.xml
@@ -31,6 +31,8 @@
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
+            <meta-data android:name="android.metadata.SLICE_URI"
+                       android:value="content://androidx.app.slice.view.test/render" />
         </activity>
     </application>
 </manifest>
diff --git a/slices/view/src/androidTest/NO_DOCS b/slices/view/src/androidTest/NO_DOCS
deleted file mode 100644
index 4dad694..0000000
--- a/slices/view/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/slices/view/src/androidTest/java/androidx/app/slice/SliceManagerTest.java b/slices/view/src/androidTest/java/androidx/app/slice/SliceManagerTest.java
index a20a5cc..3ad623f 100644
--- a/slices/view/src/androidTest/java/androidx/app/slice/SliceManagerTest.java
+++ b/slices/view/src/androidTest/java/androidx/app/slice/SliceManagerTest.java
@@ -46,6 +46,7 @@
 import java.util.List;
 import java.util.concurrent.Executor;
 
+import androidx.app.slice.render.SliceRenderActivity;
 import androidx.app.slice.widget.SliceLiveData;
 
 @RunWith(AndroidJUnit4.class)
@@ -148,6 +149,15 @@
         assertEquals(SliceLiveData.SUPPORTED_SPECS, mManager.getPinnedSpecs(uri));
     }
 
+    @Test
+    public void testMapIntentToUri() {
+        Uri expected = Uri.parse("content://androidx.app.slice.view.test/render");
+        Slice s = new Slice.Builder(expected).build();
+        when(mSliceProvider.onBindSlice(eq(expected))).thenReturn(s);
+        Uri uri = mManager.mapIntentToUri(new Intent(mContext, SliceRenderActivity.class));
+        assertEquals(expected, uri);
+    }
+
     public static class TestSliceProvider extends SliceProvider {
 
         public static SliceProvider sSliceProviderReceiver;
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
index 6cf6182..3a71268 100644
--- a/slices/view/src/androidTest/java/androidx/app/slice/render/RenderTest.java
+++ b/slices/view/src/androidTest/java/androidx/app/slice/render/RenderTest.java
@@ -16,6 +16,8 @@
 
 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;
@@ -51,5 +53,8 @@
                 .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
index 114d0e1..546f1e3 100644
--- a/slices/view/src/androidTest/java/androidx/app/slice/render/SliceCreator.java
+++ b/slices/view/src/androidTest/java/androidx/app/slice/render/SliceCreator.java
@@ -34,6 +34,7 @@
 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;
 
 /**
@@ -97,40 +98,55 @@
     }
 
     private Slice createWeather(Uri sliceUri) {
-        GridBuilder b = new GridBuilder(getContext(), sliceUri);
-        return b.addCell(new GridBuilder.CellBuilder(b)
-                        .addLargeImage(Icon.createWithResource(getContext(), R.drawable.weather_1))
+        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)
+                        .addImage(Icon.createWithResource(getContext(), R.drawable.weather_1),
+                                GridBuilder.SMALL_IMAGE)
                         .addText("MON")
                         .addTitleText("69\u00B0"))
-                .addCell(new GridBuilder.CellBuilder(b)
-                        .addLargeImage(Icon.createWithResource(getContext(), R.drawable.weather_2))
+                .addCell(new GridBuilder.CellBuilder(gb)
+                        .addImage(Icon.createWithResource(getContext(), R.drawable.weather_2),
+                                GridBuilder.SMALL_IMAGE)
                         .addText("TUE")
                         .addTitleText("71\u00B0"))
-                .addCell(new GridBuilder.CellBuilder(b)
-                        .addLargeImage(Icon.createWithResource(getContext(), R.drawable.weather_3))
+                .addCell(new GridBuilder.CellBuilder(gb)
+                        .addImage(Icon.createWithResource(getContext(), R.drawable.weather_3),
+                                GridBuilder.SMALL_IMAGE)
                         .addText("WED")
                         .addTitleText("76\u00B0"))
-                .addCell(new GridBuilder.CellBuilder(b)
-                        .addLargeImage(Icon.createWithResource(getContext(), R.drawable.weather_4))
+                .addCell(new GridBuilder.CellBuilder(gb)
+                        .addImage(Icon.createWithResource(getContext(), R.drawable.weather_4),
+                                GridBuilder.SMALL_IMAGE)
                         .addText("THU")
                         .addTitleText("72\u00B0"))
-                .addCell(new GridBuilder.CellBuilder(b)
-                        .addLargeImage(Icon.createWithResource(getContext(), R.drawable.weather_1))
+                .addCell(new GridBuilder.CellBuilder(gb)
+                        .addImage(Icon.createWithResource(getContext(), R.drawable.weather_1),
+                                GridBuilder.SMALL_IMAGE)
                         .addText("FRI")
-                        .addTitleText("68\u00B0"))
-                .build();
+                        .addTitleText("68\u00B0"));
+        return b.addGrid(gb).build();
     }
 
     private Slice createGallery(Uri sliceUri) {
-        GridBuilder b = new GridBuilder(getContext(), sliceUri);
-        return b.addCell(new GridBuilder.CellBuilder(b)
-                    .addLargeImage(Icon.createWithResource(getContext(), R.drawable.slices_1)))
-                .addCell(new GridBuilder.CellBuilder(b)
-                    .addLargeImage(Icon.createWithResource(getContext(), R.drawable.slices_2)))
-                .addCell(new GridBuilder.CellBuilder(b)
-                    .addLargeImage(Icon.createWithResource(getContext(), R.drawable.slices_3)))
-                .addCell(new GridBuilder.CellBuilder(b)
-                    .addLargeImage(Icon.createWithResource(getContext(), R.drawable.slices_4)))
+        ListBuilder b = new ListBuilder(getContext(), sliceUri);
+        GridBuilder gb = new GridBuilder(b);
+        return gb.addCell(new GridBuilder.CellBuilder(gb)
+                    .addImage(Icon.createWithResource(getContext(), R.drawable.slices_1),
+                            GridBuilder.LARGE_IMAGE))
+                .addCell(new GridBuilder.CellBuilder(gb)
+                    .addImage(Icon.createWithResource(getContext(), R.drawable.slices_2),
+                            GridBuilder.LARGE_IMAGE))
+                .addCell(new GridBuilder.CellBuilder(gb)
+                    .addImage(Icon.createWithResource(getContext(), R.drawable.slices_3),
+                            GridBuilder.LARGE_IMAGE))
+                .addCell(new GridBuilder.CellBuilder(gb)
+                    .addImage(Icon.createWithResource(getContext(), R.drawable.slices_4),
+                            GridBuilder.LARGE_IMAGE))
                 .build();
     }
 
@@ -145,19 +161,23 @@
                         .addEndItem(Icon.createWithResource(getContext(), R.drawable.mady)))
                 .addGrid(gb
                         .addCell(new GridBuilder.CellBuilder(gb)
-                            .addImage(Icon.createWithResource(getContext(), R.drawable.ic_call))
+                            .addImage(Icon.createWithResource(getContext(), R.drawable.ic_call),
+                                    GridBuilder.ICON_IMAGE)
                             .addText("Call")
                             .setContentIntent(getBroadcastIntent(ACTION_TOAST, "call")))
                         .addCell(new GridBuilder.CellBuilder(gb)
-                            .addImage(Icon.createWithResource(getContext(), R.drawable.ic_text))
+                            .addImage(Icon.createWithResource(getContext(), R.drawable.ic_text),
+                                    GridBuilder.ICON_IMAGE)
                             .addText("Text")
                             .setContentIntent(getBroadcastIntent(ACTION_TOAST, "text")))
                         .addCell(new GridBuilder.CellBuilder(gb)
-                            .addImage(Icon.createWithResource(getContext(), R.drawable.ic_video))
+                            .addImage(Icon.createWithResource(getContext(), R.drawable.ic_video),
+                                    GridBuilder.ICON_IMAGE)
                             .setContentIntent(getBroadcastIntent(ACTION_TOAST, "video"))
                             .addText("Video"))
                         .addCell(new GridBuilder.CellBuilder(gb)
-                            .addImage(Icon.createWithResource(getContext(), R.drawable.ic_email))
+                            .addImage(Icon.createWithResource(getContext(), R.drawable.ic_email),
+                                    GridBuilder.ICON_IMAGE)
                             .addText("Email")
                             .setContentIntent(getBroadcastIntent(ACTION_TOAST, "email"))))
                 .build();
@@ -190,12 +210,15 @@
                 .addRow(new ListBuilder.RowBuilder(lb)
                     .setTitle("Create new note")
                     .setSubtitle("with this note taking app")
-                    .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_create),
-                            getBroadcastIntent(ACTION_TOAST, "create note"))
-                    .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_voice),
-                            getBroadcastIntent(ACTION_TOAST, "voice note"))
-                    .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_camera),
-                            getIntent("android.media.action.IMAGE_CAPTURE")))
+                    .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();
     }
 
@@ -207,22 +230,28 @@
         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);
-
-        ListBuilder b = new ListBuilder(getContext(), sliceUri);
-        return b.setColor(0xff0F9D58)
-            .addRow(new ListBuilder.RowBuilder(b)
-                    .setContentIntent(getBroadcastIntent(ACTION_TOAST, "work"))
-                    .setTitle("Work")
-                    .setSubtitle(workSubtitle)
-                    .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_work),
-                        getBroadcastIntent(ACTION_TOAST, "work")))
-            .addRow(new ListBuilder.RowBuilder(b)
-                    .setContentIntent(getBroadcastIntent(ACTION_TOAST, "home"))
-                    .setTitle("Home")
-                    .setSubtitle(homeSubtitle)
-                    .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_home),
-                        getBroadcastIntent(ACTION_TOAST, "home")))
-            .build();
+        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) {
@@ -231,9 +260,9 @@
                 .addRow(new ListBuilder.RowBuilder(b)
                     .setTitle("Custom toggle")
                     .setSubtitle("It can support two states")
-                    .addToggle(getBroadcastIntent(ACTION_TOAST, "star toggled"),
-                            true /* isChecked */,
-                            Icon.createWithResource(getContext(), R.drawable.toggle_star)))
+                    .addEndItem(new SliceAction(getBroadcastIntent(ACTION_TOAST, "star toggled"),
+                            Icon.createWithResource(getContext(), R.drawable.toggle_star),
+                            "Toggle star", true /* isChecked */)))
                 .build();
     }
 
@@ -243,12 +272,14 @@
                 .addRow(new ListBuilder.RowBuilder(lb)
                         .setTitle("2 toggles")
                         .setSubtitle("each supports two states")
-                        .addToggle(getBroadcastIntent(ACTION_TOAST, "first star toggled"),
-                                true /* isChecked */,
-                                Icon.createWithResource(getContext(), R.drawable.toggle_star))
-                        .addToggle(getBroadcastIntent(ACTION_TOAST, "second star toggled"),
-                                false /* isChecked */,
-                                Icon.createWithResource(getContext(), R.drawable.toggle_star)))
+                        .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();
     }
 
@@ -275,13 +306,16 @@
         }
         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)
-                    .addToggle(getBroadcastIntent(ACTION_WIFI_CHANGED, null), finalWifiEnabled)
-                    .setContentIntent(getIntent(Settings.ACTION_WIFI_SETTINGS)))
+                        .addEndItem(new SliceAction(getBroadcastIntent(ACTION_WIFI_CHANGED, null),
+                                "Toggle wifi", finalWifiEnabled))
+                    .setPrimaryAction(primaryAction))
             .build();
     }
 
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
index d2b8619..dc9196e 100644
--- a/slices/view/src/androidTest/java/androidx/app/slice/render/SliceRenderer.java
+++ b/slices/view/src/androidTest/java/androidx/app/slice/render/SliceRenderer.java
@@ -23,7 +23,6 @@
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.os.AsyncTask;
-import android.os.Environment;
 import android.os.Handler;
 import android.support.v7.widget.RecyclerView;
 import android.util.Log;
@@ -46,7 +45,7 @@
 public class SliceRenderer {
 
     private static final String TAG = "SliceRenderer";
-    private static final String SCREENSHOT_DIR = "slice-screenshots";
+    public static final String SCREENSHOT_DIR = "slice-screenshots";
     private static File sScreenshotDirectory;
 
     private final Activity mContext;
@@ -66,7 +65,7 @@
             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,
+                int height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 300,
                         mContext.getResources().getDisplayMetrics());
                 mLayout.measure(makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
                         makeMeasureSpec(height, View.MeasureSpec.EXACTLY));
@@ -106,9 +105,9 @@
     }
 
 
-    private static File getScreenshotDirectory() {
+    private File getScreenshotDirectory() {
         if (sScreenshotDirectory == null) {
-            File storage = Environment.getExternalStorageDirectory();
+            File storage = mContext.getDataDir();
             sScreenshotDirectory = new File(storage, SCREENSHOT_DIR);
             if (!sScreenshotDirectory.exists()) {
                 if (!sScreenshotDirectory.mkdirs()) {
diff --git a/slices/view/src/main/java/androidx/app/slice/SliceManager.java b/slices/view/src/main/java/androidx/app/slice/SliceManager.java
index ba8c376..6d44319 100644
--- a/slices/view/src/main/java/androidx/app/slice/SliceManager.java
+++ b/slices/view/src/main/java/androidx/app/slice/SliceManager.java
@@ -150,6 +150,19 @@
     public abstract @Nullable Slice bindSlice(@NonNull Intent intent);
 
     /**
+     * Turns a slice intent into a slice uri. 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 Uri provided by the app or null if none is given.
+     * @see Slice
+     * @see SliceProvider#onMapIntentToUri(Intent)
+     * @see Intent
+     */
+    public abstract @Nullable Uri mapIntentToUri(@NonNull Intent intent);
+
+    /**
      * Class that listens to changes in {@link Slice}s.
      */
     public interface SliceCallback {
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
index 67613a5..433afd5 100644
--- a/slices/view/src/main/java/androidx/app/slice/SliceManagerCompat.java
+++ b/slices/view/src/main/java/androidx/app/slice/SliceManagerCompat.java
@@ -20,19 +20,12 @@
 
 import android.content.Context;
 import android.content.Intent;
-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.Nullable;
 import android.support.annotation.RestrictTo;
-import android.util.ArrayMap;
-import android.util.Pair;
 
 import java.util.List;
-import java.util.concurrent.Executor;
 
 import androidx.app.slice.compat.SliceProviderCompat;
 import androidx.app.slice.widget.SliceLiveData;
@@ -42,38 +35,10 @@
  * @hide
  */
 @RestrictTo(RestrictTo.Scope.LIBRARY)
-class SliceManagerCompat extends SliceManager {
-    private final ArrayMap<Pair<Uri, SliceCallback>, SliceListenerImpl> mListenerLookup =
-            new ArrayMap<>();
-    private final Context mContext;
+class SliceManagerCompat extends SliceManagerBase {
 
     SliceManagerCompat(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();
+        super(context);
     }
 
     @Override
@@ -103,55 +68,9 @@
         return SliceProviderCompat.bindSlice(mContext, intent, SUPPORTED_SPECS);
     }
 
-    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);
-            }
-        };
+    @Nullable
+    @Override
+    public Uri mapIntentToUri(@NonNull Intent intent) {
+        return SliceProviderCompat.mapIntentToUri(mContext, intent);
     }
 }
diff --git a/slices/view/src/main/java/androidx/app/slice/SliceManagerWrapper.java b/slices/view/src/main/java/androidx/app/slice/SliceManagerWrapper.java
index 8b2265c..76c6a4a 100644
--- a/slices/view/src/main/java/androidx/app/slice/SliceManagerWrapper.java
+++ b/slices/view/src/main/java/androidx/app/slice/SliceManagerWrapper.java
@@ -19,7 +19,6 @@
 import static androidx.app.slice.SliceConvert.unwrap;
 import static androidx.app.slice.widget.SliceLiveData.SUPPORTED_SPECS;
 
-import android.app.slice.Slice;
 import android.app.slice.SliceSpec;
 import android.content.Context;
 import android.content.Intent;
@@ -30,50 +29,28 @@
 import android.support.annotation.RestrictTo;
 
 import java.util.List;
-import java.util.WeakHashMap;
-import java.util.concurrent.Executor;
 
 /**
  * @hide
  */
 @RestrictTo(RestrictTo.Scope.LIBRARY)
 @RequiresApi(api = 28)
-class SliceManagerWrapper extends SliceManager {
+class SliceManagerWrapper extends SliceManagerBase {
+
     private final android.app.slice.SliceManager mManager;
-    private final WeakHashMap<SliceCallback, android.app.slice.SliceManager.SliceCallback>
-            mCallbacks = new WeakHashMap<>();
     private final List<SliceSpec> mSpecs;
-    private final Context mContext;
 
     SliceManagerWrapper(Context context) {
         this(context, context.getSystemService(android.app.slice.SliceManager.class));
     }
 
     SliceManagerWrapper(Context context, android.app.slice.SliceManager manager) {
-        mContext = context;
+        super(context);
         mManager = manager;
         mSpecs = unwrap(SUPPORTED_SPECS);
     }
 
     @Override
-    public void registerSliceCallback(@NonNull Uri uri,
-            @NonNull SliceCallback callback) {
-        mManager.registerSliceCallback(uri, addCallback(callback), mSpecs);
-    }
-
-    @Override
-    public void registerSliceCallback(@NonNull Uri uri, @NonNull Executor executor,
-            @NonNull SliceCallback callback) {
-        mManager.registerSliceCallback(uri, addCallback(callback), mSpecs, executor);
-    }
-
-    @Override
-    public void unregisterSliceCallback(@NonNull Uri uri,
-            @NonNull SliceCallback callback) {
-        mManager.unregisterSliceCallback(uri, mCallbacks.get(callback));
-    }
-
-    @Override
     public void pinSlice(@NonNull Uri uri) {
         mManager.pinSlice(uri, mSpecs);
     }
@@ -92,27 +69,21 @@
     @Override
     public androidx.app.slice.Slice bindSlice(@NonNull Uri uri) {
         return SliceConvert.wrap(android.app.slice.Slice.bindSlice(
-                mContext.getContentResolver(), uri, unwrap(SUPPORTED_SPECS)));
+                mContext.getContentResolver(), uri, mSpecs));
     }
 
     @Nullable
     @Override
     public androidx.app.slice.Slice bindSlice(@NonNull Intent intent) {
         return SliceConvert.wrap(android.app.slice.Slice.bindSlice(
-                mContext, intent, unwrap(SUPPORTED_SPECS)));
+                mContext, intent, mSpecs));
     }
 
-    private android.app.slice.SliceManager.SliceCallback addCallback(final SliceCallback callback) {
-        android.app.slice.SliceManager.SliceCallback ret = mCallbacks.get(callback);
-        if (ret == null) {
-            ret = new android.app.slice.SliceManager.SliceCallback() {
-                @Override
-                public void onSliceUpdated(Slice s) {
-                    callback.onSliceUpdated(SliceConvert.wrap(s));
-                }
-            };
-            mCallbacks.put(callback, ret);
-        }
-        return ret;
+    @Nullable
+    @Override
+    public Uri mapIntentToUri(@NonNull Intent intent) {
+        // TODO: Switch over to mapIntentToUri once it lands in prebuilt.
+        Slice slice = bindSlice(intent);
+        return slice != null ? slice.getUri() : null;
     }
 }
diff --git a/slices/view/src/main/java/androidx/app/slice/SliceUtils.java b/slices/view/src/main/java/androidx/app/slice/SliceUtils.java
index 6a6ab14..117aee3 100644
--- a/slices/view/src/main/java/androidx/app/slice/SliceUtils.java
+++ b/slices/view/src/main/java/androidx/app/slice/SliceUtils.java
@@ -16,19 +16,24 @@
 
 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;
 
@@ -188,7 +193,7 @@
      * @see #LOADING_PARTIAL
      * @see #LOADING_COMPLETE
      */
-    public static int getLoadingState(Slice slice) {
+    public static int getLoadingState(@NonNull Slice slice) {
         // Check loading state
         boolean hasHintPartial =
                 SliceQuery.find(slice, null, HINT_PARTIAL, null) != null;
@@ -203,4 +208,16 @@
             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/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
index 2eaa059..f517061 100644
--- a/slices/view/src/main/java/androidx/app/slice/widget/ActionRow.java
+++ b/slices/view/src/main/java/androidx/app/slice/widget/ActionRow.java
@@ -17,7 +17,6 @@
 package androidx.app.slice.widget;
 
 import static android.app.slice.Slice.HINT_NO_TINT;
-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;
 
@@ -25,11 +24,12 @@
 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.os.AsyncTask;
+import android.support.annotation.NonNull;
 import android.support.annotation.RestrictTo;
 import android.util.TypedValue;
 import android.view.View;
@@ -40,6 +40,7 @@
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
+import java.util.List;
 import java.util.function.Consumer;
 
 import androidx.app.slice.SliceItem;
@@ -103,26 +104,24 @@
     /**
      * Set the actions and color for this action row.
      */
-    public void setActions(SliceItem actionRow, int color) {
+    public void setActions(@NonNull List<SliceItem> actions, int color) {
         removeAllViews();
         mActionsGroup.removeAllViews();
         addView(mActionsGroup);
         if (color != -1) {
             setColor(color);
         }
-        SliceQuery.findAll(actionRow, FORMAT_ACTION).forEach(new Consumer<SliceItem>() {
+        actions.forEach(new Consumer<SliceItem>() {
             @Override
             public void accept(final SliceItem action) {
                 if (mActionsGroup.getChildCount() >= MAX_ACTIONS) {
                     return;
                 }
-                SliceItem image = SliceQuery.find(action, FORMAT_IMAGE);
-                if (image == null) {
-                    return;
-                }
-                boolean tint = !image.hasHint(HINT_NO_TINT);
                 final SliceItem input = SliceQuery.find(action, FORMAT_REMOTE_INPUT);
-                if (input != null && input.getRemoteInput().getAllowFreeFormInput()) {
+                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
@@ -132,24 +131,23 @@
                                 }
                             });
                     createRemoteInputView(mColor, getContext());
-                } else {
-                    addAction(image.getIcon(), tint, image).setOnClickListener(
-                            new OnClickListener() {
-                                @Override
-                                public void onClick(View v) {
-                                    AsyncTask.execute(new Runnable() {
-                                        @Override
-                                        public void run() {
-
-                                            try {
-                                                action.getAction().send();
-                                            } catch (CanceledException e) {
-                                                e.printStackTrace();
-                                            }
+                } 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();
                                         }
-                                    });
-                                }
-                            });
+                                    }
+                                });
+                    }
                 }
             }
         });
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
index 9569dc0..10a30ac 100644
--- a/slices/view/src/main/java/androidx/app/slice/widget/GridContent.java
+++ b/slices/view/src/main/java/androidx/app/slice/widget/GridContent.java
@@ -16,6 +16,9 @@
 
 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;
@@ -24,13 +27,20 @@
 import static android.app.slice.SliceItem.FORMAT_TEXT;
 import static android.app.slice.SliceItem.FORMAT_TIMESTAMP;
 
+import android.app.slice.Slice;
+import android.content.Context;
+import android.content.res.Resources;
+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.builders.GridBuilder;
 import androidx.app.slice.core.SliceQuery;
+import androidx.app.slice.view.R;
 
 /**
  * Extracts information required to present content in a grid format from a slice.
@@ -40,27 +50,53 @@
 public class GridContent {
 
     private boolean mAllImages;
-    public SliceItem mColorItem;
-    public ArrayList<CellContent> mGridContent = new ArrayList<>();
+    private SliceItem mColorItem;
+    private SliceItem mPrimaryAction;
+    private ArrayList<CellContent> mGridContent = new ArrayList<>();
+    private int mMaxCellLineCount;
+    private boolean mHasImage;
+    private @GridBuilder.ImageMode int mLargestImageMode;
 
-    public GridContent(SliceItem gridItem) {
+    private int mBigPicMinHeight;
+    private int mBigPicMaxHeight;
+    private int mAllImagesHeight;
+    private int mImageTextHeight;
+    private int mMaxHeight;
+    private int mMinHeight;
+
+    public GridContent(Context context, SliceItem gridItem) {
         populate(gridItem);
+
+        Resources res = context.getResources();
+        mBigPicMinHeight = res.getDimensionPixelSize(R.dimen.abc_slice_big_pic_min_height);
+        mBigPicMaxHeight = res.getDimensionPixelSize(R.dimen.abc_slice_big_pic_max_height);
+        mAllImagesHeight = res.getDimensionPixelSize(R.dimen.abc_slice_grid_image_only_height);
+        mImageTextHeight = res.getDimensionPixelSize(R.dimen.abc_slice_grid_image_text_height);
+        mMinHeight = res.getDimensionPixelSize(R.dimen.abc_slice_grid_min_height);
+        mMaxHeight = res.getDimensionPixelSize(R.dimen.abc_slice_grid_max_height);
     }
 
     private void reset() {
         mColorItem = null;
+        mMaxCellLineCount = 0;
+        mHasImage = false;
         mGridContent.clear();
+        mLargestImageMode = 0;
     }
 
     /**
      * @return whether this grid has content that is valid to display.
      */
-    public boolean populate(SliceItem gridItem) {
+    private 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();
@@ -68,25 +104,31 @@
             for (int i = 0; i < items.size(); i++) {
                 SliceItem item = items.get(i);
                 CellContent cc = new CellContent(item);
-                if (cc.isValid()) {
-                    mGridContent.add(cc);
-                    if (!cc.isImageOnly()) {
-                        mAllImages = false;
-                    }
-                }
+                processContent(cc);
             }
         } else {
             CellContent cc = new CellContent(gridItem);
-            if (cc.isValid()) {
-                mGridContent.add(cc);
-            }
+            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();
+            mLargestImageMode = Math.max(mLargestImageMode, cc.getImageMode());
+        }
+    }
+
     /**
      * @return the list of cell content for this grid.
      */
+    @NonNull
     public ArrayList<CellContent> getGridContent() {
         return mGridContent;
     }
@@ -94,11 +136,20 @@
     /**
      * @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() {
@@ -112,6 +163,62 @@
         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;
+    }
+
+    /**
+     * @return the height to display a grid row at when it is used as a small template.
+     */
+    public int getSmallHeight() {
+        return getHeight(true /* isSmall */);
+    }
+
+    /**
+     * @return the height the content in this template requires to be displayed.
+     */
+    public int getActualHeight() {
+        return getHeight(false /* isSmall */);
+    }
+
+    private int getHeight(boolean isSmall) {
+        if (!isValid()) {
+            return 0;
+        }
+        if (mAllImages) {
+            return mGridContent.size() == 1
+                    ? isSmall ? mBigPicMinHeight : mBigPicMaxHeight
+                    : mLargestImageMode == GridBuilder.ICON_IMAGE ? mMinHeight : mAllImagesHeight;
+        } else {
+            boolean twoLines = getMaxCellLineCount() > 1;
+            boolean hasImage = hasImage();
+            return (twoLines && !isSmall)
+                    ? hasImage ? mMaxHeight : mMinHeight
+                    : mLargestImageMode == GridBuilder.ICON_IMAGE ? mMinHeight : mImageTextHeight;
+        }
+    }
+
     /**
      * Extracts information required to present content in a cell.
      * @hide
@@ -120,6 +227,9 @@
     public static class CellContent {
         private SliceItem mContentIntent;
         private ArrayList<SliceItem> mCellItems = new ArrayList<>();
+        private int mTextCount;
+        private boolean mHasImage;
+        private int mImageMode = -1;
 
         public CellContent(SliceItem cellItem) {
             populate(cellItem);
@@ -130,7 +240,8 @@
          */
         public boolean populate(SliceItem cellItem) {
             final String format = cellItem.getFormat();
-            if (FORMAT_SLICE.equals(format) || FORMAT_ACTION.equals(format)) {
+            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())
@@ -141,17 +252,25 @@
                 if (FORMAT_ACTION.equals(format)) {
                     mContentIntent = cellItem;
                 }
-                int textCount = 0;
+                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 (textCount < 2 && (FORMAT_TEXT.equals(itemFormat)
+                    if (mTextCount < 2 && (FORMAT_TEXT.equals(itemFormat)
                             || FORMAT_TIMESTAMP.equals(itemFormat))) {
-                        textCount++;
+                        mTextCount++;
                         mCellItems.add(item);
                     } else if (imageCount < 1 && FORMAT_IMAGE.equals(item.getFormat())) {
+                        if (item.hasHint(Slice.HINT_NO_TINT)) {
+                            mImageMode = item.hasHint(Slice.HINT_LARGE)
+                                    ? GridBuilder.LARGE_IMAGE
+                                    : GridBuilder.SMALL_IMAGE;
+                        } else {
+                            mImageMode = GridBuilder.ICON_IMAGE;
+                        }
                         imageCount++;
+                        mHasImage = true;
                         mCellItems.add(item);
                     }
                 }
@@ -198,5 +317,26 @@
         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;
+        }
+
+        /**
+         * @return the mode of the image.
+         */
+        public int getImageMode() {
+            return mImageMode;
+        }
     }
 }
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
index a5959d3..148730c 100644
--- a/slices/view/src/main/java/androidx/app/slice/widget/GridRowView.java
+++ b/slices/view/src/main/java/androidx/app/slice/widget/GridRowView.java
@@ -26,6 +26,8 @@
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 
+import static androidx.app.slice.widget.SliceView.MODE_SMALL;
+
 import android.annotation.TargetApi;
 import android.app.PendingIntent;
 import android.content.Context;
@@ -67,15 +69,11 @@
 
     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;
+    private static final int MAX_CELLS = 5;
 
     // Max number of text items that can show in a cell
     private static final int MAX_CELL_TEXT = 2;
@@ -85,13 +83,10 @@
     private static final int MAX_CELL_IMAGES = 1;
 
     private int mRowIndex;
-    private boolean mIsAllImages;
-    private @SliceView.SliceMode int mSliceMode = 0;
-
+    private int mSmallImageSize;
     private int mIconSize;
-    private int mLargeIconSize;
-    private int mBigPictureHeight;
-    private int mAllImagesHeight;
+    private int mGutter;
+
     private GridContent mGridContent;
     private LinearLayout mViewContainer;
 
@@ -102,61 +97,58 @@
     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));
+        mViewContainer.setGravity(Gravity.CENTER_VERTICAL);
+        mIconSize = res.getDimensionPixelSize(R.dimen.abc_slice_icon_size);
+        mSmallImageSize = res.getDimensionPixelSize(R.dimen.abc_slice_small_image_size);
+        mGutter = res.getDimensionPixelSize(R.dimen.abc_slice_grid_gutter);
+    }
+
+    @Override
+    public int getSmallHeight() {
+        // GridRow is small if its the first element in a list without a header presented in small
+        return mGridContent != null ? mGridContent.getSmallHeight() : 0;
+    }
+
+    @Override
+    public int getActualHeight() {
+        return mGridContent != null ? mGridContent.getActualHeight() : 0;
     }
 
     @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;
-            }
-        }
+        int height = getMode() == MODE_SMALL ? getSmallHeight() : getActualHeight();
+        heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
+        mViewContainer.getLayoutParams().height = height;
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
     }
 
     @Override
-    public int getMode() {
-        return mSliceMode;
-    }
-
-    @Override
     public void setTint(@ColorInt int tintColor) {
         super.setTint(tintColor);
         if (mGridContent != null) {
+            GridContent gc = mGridContent;
             // TODO -- could be smarter about this
             resetView();
-            populateViews(mGridContent);
+            populateViews(gc);
         }
     }
 
     /**
-     * This is called when GridView is being used as a small template.
+     * This is called when GridView is presented in small format.
      */
     @Override
     public void setSlice(Slice slice) {
         resetView();
         mRowIndex = 0;
-        mSliceMode = SliceView.MODE_SMALL;
-        Slice.Builder sb = new Slice.Builder(slice.getUri());
-        sb.addSubSlice(slice);
-        Slice parentSlice = sb.build();
-        mGridContent = new GridContent(parentSlice.getItems().get(0));
+        mGridContent = new GridContent(getContext(), slice.getItems().get(0));
         populateViews(mGridContent);
     }
 
     /**
-     * This is called when GridView is being used as a component in a large template.
+     * 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,
@@ -164,23 +156,25 @@
         resetView();
         setSliceActionListener(observer);
         mRowIndex = index;
-        mSliceMode = SliceView.MODE_LARGE;
-        mGridContent = new GridContent(slice);
+        mGridContent = new GridContent(getContext(), slice);
         populateViews(mGridContent);
     }
 
     private void populateViews(GridContent gc) {
-        mIsAllImages = gc.isAllImages();
+        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);
+        }
         ArrayList<GridContent.CellContent> cells = gc.getGridContent();
-        final int max = mIsAllImages ? MAX_IMAGES : MAX_ALL;
         for (int i = 0; i < cells.size(); i++) {
-            if (isFull()) {
+            if (mViewContainer.getChildCount() >= MAX_CELLS) {
+                // TODO -- use item if it exists
                 break;
             }
-            addCell(cells.get(i), i, Math.min(cells.size(), max));
-        }
-        if (ALLOW_SEE_MORE && mIsAllImages && cells.size() > getChildCount()) {
-            addSeeMoreCount(cells.size() - getChildCount());
+            addCell(cells.get(i), i, Math.min(cells.size(), MAX_CELLS));
         }
     }
 
@@ -203,15 +197,11 @@
         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 = mSliceMode == SliceView.MODE_SMALL
+        final int maxCellText = getMode() == MODE_SMALL
                 ? MAX_CELL_TEXT_SMALL
                 : MAX_CELL_TEXT;
         LinearLayout cellContainer = new LinearLayout(getContext());
@@ -227,7 +217,7 @@
         boolean singleItem = cellItems.size() == 1;
         List<SliceItem> textItems = null;
         // In small format we display one text item and prefer titles
-        if (!singleItem && mSliceMode == SliceView.MODE_SMALL) {
+        if (!singleItem && getMode() == MODE_SMALL) {
             // Get all our text items
             textItems = cellItems.stream().filter(new Predicate<SliceItem>() {
                 @Override
@@ -266,11 +256,17 @@
         if (added) {
             mViewContainer.addView(cellContainer,
                     new LinearLayout.LayoutParams(0, WRAP_CONTENT, 1));
+            if (index != total - 1) {
+                // If we're not the last or only element add space between items
+                MarginLayoutParams lp =
+                        (LinearLayout.MarginLayoutParams) cellContainer.getLayoutParams();
+                lp.setMarginEnd(mGutter);
+            }
             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);
+                Pair<SliceItem, EventInfo> tagItem = new Pair<>(contentIntentItem, info);
                 cellContainer.setTag(tagItem);
                 makeClickable(cellContainer);
             }
@@ -299,15 +295,20 @@
         } 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;
+            LinearLayout.LayoutParams lp;
             if (item.hasHint(HINT_LARGE)) {
                 iv.setScaleType(ScaleType.CENTER_CROP);
-                size = singleItem ? MATCH_PARENT : mLargeIconSize;
+                lp = new LinearLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT);
+            } else {
+                boolean isIcon = !item.hasHint(HINT_NO_TINT);
+                int size = isIcon ? mIconSize : mSmallImageSize;
+                iv.setScaleType(isIcon ? ScaleType.CENTER_INSIDE : ScaleType.CENTER_CROP);
+                lp = new LinearLayout.LayoutParams(size, size);
             }
-            container.addView(iv, new LayoutParams(size, size));
+            if (color != -1 && !item.hasHint(HINT_NO_TINT)) {
+                iv.setColorFilter(color);
+            }
+            container.addView(iv, lp);
             addedView = iv;
         }
         return addedView != null;
@@ -338,7 +339,6 @@
 
     @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
index 45f659d..b64cd01 100644
--- a/slices/view/src/main/java/androidx/app/slice/widget/LargeSliceAdapter.java
+++ b/slices/view/src/main/java/androidx/app/slice/widget/LargeSliceAdapter.java
@@ -23,6 +23,8 @@
 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;
@@ -61,10 +63,10 @@
     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;
@@ -76,6 +78,16 @@
     }
 
     /**
+     * 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) {
@@ -128,24 +140,32 @@
     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, position == 0 /* isHeader */,
-                    position, mSliceObserver);
+            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:
-                return LayoutInflater.from(mContext).inflate(R.layout.abc_slice_grid, null);
+                v = LayoutInflater.from(mContext).inflate(R.layout.abc_slice_grid, null);
+                break;
             case TYPE_MESSAGE:
-                return LayoutInflater.from(mContext).inflate(R.layout.abc_slice_message, null);
+                v = LayoutInflater.from(mContext).inflate(R.layout.abc_slice_message, null);
+                break;
             case TYPE_MESSAGE_LOCAL:
-                return LayoutInflater.from(mContext).inflate(R.layout.abc_slice_message_local,
+                v = LayoutInflater.from(mContext).inflate(R.layout.abc_slice_message_local,
                         null);
+                break;
         }
-        return new RowView(mContext);
+        ((SliceChildView) v).setMode(MODE_LARGE);
+        return v;
     }
 
     protected static class SliceWrapper {
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
index d015893..bdd1ac5 100644
--- a/slices/view/src/main/java/androidx/app/slice/widget/LargeTemplateView.java
+++ b/slices/view/src/main/java/androidx/app/slice/widget/LargeTemplateView.java
@@ -16,9 +16,6 @@
 
 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;
@@ -26,9 +23,10 @@
 import android.support.v7.widget.RecyclerView;
 import android.util.AttributeSet;
 
+import java.util.List;
+
 import androidx.app.slice.Slice;
-import androidx.app.slice.core.SliceQuery;
-import androidx.app.slice.view.R;
+import androidx.app.slice.SliceItem;
 
 /**
  * @hide
@@ -39,9 +37,9 @@
 
     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);
@@ -50,7 +48,11 @@
         mAdapter = new LargeSliceAdapter(context);
         mRecyclerView.setAdapter(mAdapter);
         addView(mRecyclerView);
-        mDefaultHeight = getResources().getDimensionPixelSize(R.dimen.abc_slice_large_height);
+    }
+
+    @Override
+    public int getActualHeight() {
+        return mListContent != null ? mListContent.getListHeight() : 0;
     }
 
     @Override
@@ -73,17 +75,8 @@
     }
 
     @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);
+    public void setSliceActions(List<SliceItem> actions) {
+        mAdapter.setSliceActions(actions);
     }
 
     @Override
@@ -102,8 +95,8 @@
         if (mSlice == null) {
             return;
         }
-        ListContent lc = new ListContent(mSlice);
-        mAdapter.setSliceItems(lc.getRowItems(), mTintColor);
+        mListContent = new ListContent(getContext(), mSlice);
+        mAdapter.setSliceItems(mListContent.getRowItems(), mTintColor);
     }
 
     /**
@@ -118,5 +111,6 @@
     public void resetView() {
         mSlice = null;
         mAdapter.setSliceItems(null, -1);
+        mListContent = null;
     }
 }
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
index d74230c..246ef0b 100644
--- a/slices/view/src/main/java/androidx/app/slice/widget/ListContent.java
+++ b/slices/view/src/main/java/androidx/app/slice/widget/ListContent.java
@@ -17,13 +17,16 @@
 package androidx.app.slice.widget;
 
 import static android.app.slice.Slice.HINT_ACTIONS;
+import static android.app.slice.Slice.HINT_HORIZONTAL;
 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.content.Context;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.annotation.RestrictTo;
@@ -33,6 +36,7 @@
 
 import androidx.app.slice.Slice;
 import androidx.app.slice.SliceItem;
+import androidx.app.slice.SliceUtils;
 import androidx.app.slice.core.SliceQuery;
 
 /**
@@ -46,8 +50,10 @@
     private SliceItem mColorItem;
     private ArrayList<SliceItem> mRowItems = new ArrayList<>();
     private List<SliceItem> mSliceActions;
+    private Context mContext;
 
-    public ListContent(Slice slice) {
+    public ListContent(Context context, Slice slice) {
+        mContext = context;
         populate(slice);
     }
 
@@ -63,15 +69,11 @@
     /**
      * @return whether this row has content that is valid to display.
      */
-    public boolean populate(Slice slice) {
+    private boolean populate(Slice slice) {
         reset();
         mColorItem = SliceQuery.findSubtype(slice, FORMAT_INT, SUBTYPE_COLOR);
         // Find slice actions
-        SliceItem actionGroup = SliceQuery.find(slice, FORMAT_SLICE, HINT_ACTIONS, null);
-        if (actionGroup != null) {
-            // TODO: actually use the actions
-            mSliceActions = SliceQuery.findAll(actionGroup, FORMAT_ACTION, HINT_ACTIONS, null);
-        }
+        mSliceActions = SliceUtils.getSliceActions(slice);
         // Find header
         mHeaderItem = findHeaderItem(slice);
         if (mHeaderItem != null) {
@@ -100,6 +102,24 @@
     }
 
     /**
+     * @return the total height of all the rows contained in this list.
+     */
+    public int getListHeight() {
+        int height = 0;
+        for (int i = 0; i < mRowItems.size(); i++) {
+            SliceItem item = mRowItems.get(i);
+            if (item.hasHint(HINT_HORIZONTAL)) {
+                GridContent gc = new GridContent(mContext, item);
+                height += gc.getActualHeight();
+            } else {
+                RowContent rc = new RowContent(mContext, item, i == 0 /* isHeader */);
+                height += rc.getActualHeight();
+            }
+        }
+        return height;
+    }
+
+    /**
      * @return whether this list has content that is valid to display.
      */
     public boolean isValid() {
@@ -135,7 +155,8 @@
     @Nullable
     private static SliceItem findHeaderItem(@NonNull Slice slice) {
         // See if header is specified
-        SliceItem header = SliceQuery.find(slice, FORMAT_SLICE, null, HINT_LIST_ITEM);
+        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;
         }
@@ -143,7 +164,8 @@
     }
 
     private static boolean isValidHeader(SliceItem sliceItem) {
-        if (FORMAT_SLICE.equals(sliceItem.getFormat()) && !sliceItem.hasHint(HINT_LIST_ITEM)) {
+        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;
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
index 52c1f02..a22a37d 100644
--- a/slices/view/src/main/java/androidx/app/slice/widget/RowContent.java
+++ b/slices/view/src/main/java/androidx/app/slice/widget/RowContent.java
@@ -16,6 +16,8 @@
 
 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;
@@ -28,8 +30,10 @@
 
 import static androidx.app.slice.core.SliceHints.SUBTYPE_RANGE;
 
+import android.content.Context;
 import android.support.annotation.Nullable;
 import android.support.annotation.RestrictTo;
+import android.text.TextUtils;
 import android.util.Log;
 
 import java.util.ArrayList;
@@ -37,6 +41,7 @@
 
 import androidx.app.slice.SliceItem;
 import androidx.app.slice.core.SliceQuery;
+import androidx.app.slice.view.R;
 
 /**
  * Extracts information required to present content in a row format from a slice.
@@ -46,7 +51,7 @@
 public class RowContent {
     private static final String TAG = "RowContent";
 
-    private SliceItem mContentIntent;
+    private SliceItem mPrimaryAction;
     private SliceItem mStartItem;
     private SliceItem mTitleItem;
     private SliceItem mSubtitleItem;
@@ -55,56 +60,69 @@
     private boolean mEndItemsContainAction;
     private SliceItem mRange;
     private boolean mIsHeader;
+    private int mLineCount = 0;
+    private int mMaxHeight;
+    private int mMinHeight;
 
-    public RowContent(SliceItem rowSlice, boolean isHeader) {
+    public RowContent(Context context, SliceItem rowSlice, boolean isHeader) {
         populate(rowSlice, isHeader);
+        mMaxHeight = context.getResources().getDimensionPixelSize(R.dimen.abc_slice_row_max_height);
+        mMinHeight = context.getResources().getDimensionPixelSize(R.dimen.abc_slice_row_min_height);
     }
 
     /**
      * Resets the content.
      */
     public void reset() {
-        mContentIntent = null;
+        mPrimaryAction = null;
         mStartItem = null;
         mTitleItem = null;
         mSubtitleItem = null;
         mEndItems.clear();
         mIsHeader = false;
+        mLineCount = 0;
     }
 
     /**
      * @return whether this row has content that is valid to display.
      */
-    public boolean populate(SliceItem rowSlice, boolean isHeader) {
+    private 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()))) {
+                || 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);
             }
         }
-        // Content intent
-        if (FORMAT_ACTION.equals(rowSlice.getFormat())) {
-            mContentIntent = rowSlice;
-        }
         if (SUBTYPE_RANGE.equals(rowSlice.getSubType())) {
             mRange = rowSlice;
         }
         if (rowItems.size() > 0) {
             // Start item
-            if (isStartType(rowItems.get(0))) {
-                mStartItem = rowItems.get(0);
-                rowItems.remove(0);
+            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++) {
@@ -122,12 +140,20 @@
                     endItems.add(item);
                 }
             }
+            if (hasText(mTitleItem)) {
+                mLineCount++;
+            }
+            if (hasText(mSubtitleItem)) {
+                mLineCount++;
+            }
             // 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;
@@ -136,10 +162,10 @@
                 } else if (desiredFormat == null) {
                     desiredFormat = item.getFormat();
                     mEndItems.add(item);
-                    mEndItemsContainAction |= FORMAT_ACTION.equals(item.getFormat());
+                    mEndItemsContainAction |= isAction;
                 } else if (desiredFormat.equals(item.getFormat())) {
                     mEndItems.add(item);
-                    mEndItemsContainAction |= FORMAT_ACTION.equals(item.getFormat());
+                    mEndItemsContainAction |= isAction;
                 }
             }
         }
@@ -165,8 +191,8 @@
     }
 
     @Nullable
-    public SliceItem getContentIntent() {
-        return mContentIntent;
+    public SliceItem getPrimaryAction() {
+        return mPrimaryAction;
     }
 
     @Nullable
@@ -194,13 +220,40 @@
     }
 
     /**
-     * @return whether {@link #getEndItems()} contains a SliceItem with FORMAT_ACTION
+     * @return whether {@link #getEndItems()} contains a SliceItem with FORMAT_SLICE, HINT_SHORTCUT
      */
     public boolean endItemsContainAction() {
         return mEndItemsContainAction;
     }
 
     /**
+     * @return the number of lines of text contained in this row.
+     */
+    public int getLineCount() {
+        return mLineCount;
+    }
+
+    /**
+     * @return the height to display a row at when it is used as a small template.
+     */
+    public int getSmallHeight() {
+        return mMaxHeight;
+    }
+
+    /**
+     * @return the height the content in this template requires to be displayed.
+     */
+    public int getActualHeight() {
+        return isValid()
+                ? (getLineCount() > 1 || mIsHeader) ? mMaxHeight : mMinHeight
+                : 0;
+    }
+
+    private static boolean hasText(SliceItem textSlice) {
+        return textSlice != null && !TextUtils.isEmpty(textSlice.getText());
+    }
+
+    /**
      * @return whether this is a valid item to use to populate a row of content.
      */
     private static boolean isValidRow(SliceItem rowSlice) {
@@ -232,16 +285,22 @@
     }
 
     /**
-     * @return whether this item has valid content to display in a row.
+     * @return whether this item is valid content to display in a row.
      */
     private static boolean isValidRowContent(SliceItem slice, SliceItem item) {
-        // TODO -- filter for shortcut once that's in
+        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();
-        // Must be a format that is presentable
         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()));
     }
@@ -252,9 +311,8 @@
      */
     private static boolean isStartType(SliceItem item) {
         final String type = item.getFormat();
-        return item.hasHint(HINT_TITLE)
-                && ((FORMAT_ACTION.equals(type) && (SliceQuery.find(item, FORMAT_IMAGE) != null))
+        return (FORMAT_ACTION.equals(type) && (SliceQuery.find(item, FORMAT_IMAGE) != null))
                     || FORMAT_IMAGE.equals(type)
-                    || FORMAT_TIMESTAMP.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
index 3a472ad..bcd4f61 100644
--- a/slices/view/src/main/java/androidx/app/slice/widget/RowView.java
+++ b/slices/view/src/main/java/androidx/app/slice/widget/RowView.java
@@ -18,17 +18,17 @@
 
 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_SELECTED;
+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_LARGE;
 import static androidx.app.slice.widget.SliceView.MODE_SMALL;
 
 import android.annotation.TargetApi;
@@ -85,11 +85,11 @@
     private SeekBar mSeekBar;
     private ProgressBar mProgressBar;
 
-    private boolean mInSmallMode;
     private int mRowIndex;
     private RowContent mRowContent;
-    private SliceItem mRowAction;
+    private ActionContent mRowAction;
     private boolean mIsHeader;
+    private List<SliceItem> mHeaderActions;
 
     private int mIconSize;
     private int mPadding;
@@ -110,9 +110,16 @@
         mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);
     }
 
+
     @Override
-    public @SliceView.SliceMode int getMode() {
-        return mInSmallMode ? MODE_SMALL : MODE_LARGE;
+    public int getSmallHeight() {
+        // RowView is in small format when it is the header of a list and displays at max height.
+        return mRowContent != null && mRowContent.isValid() ? mRowContent.getSmallHeight() : 0;
+    }
+
+    @Override
+    public int getActualHeight() {
+        return mRowContent != null && mRowContent.isValid() ? mRowContent.getActualHeight() : 0;
     }
 
     @Override
@@ -120,11 +127,25 @@
         super.setTint(tintColor);
         if (mRowContent != null) {
             // TODO -- can be smarter about this
-            resetView();
             populateViews();
         }
     }
 
+    @Override
+    public void setSliceActions(List<SliceItem> actions) {
+        mHeaderActions = actions;
+        if (mRowContent != null) {
+            populateViews();
+        }
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        int height = getMode() == MODE_SMALL ? getSmallHeight() : getActualHeight();
+        heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+    }
+
     /**
      * This is called when RowView is being used as a component in a large template.
      */
@@ -132,10 +153,10 @@
     public void setSliceItem(SliceItem slice, boolean isHeader, int index,
             SliceView.OnSliceActionListener observer) {
         setSliceActionListener(observer);
-        mInSmallMode = false;
         mRowIndex = index;
         mIsHeader = isHeader;
-        mRowContent = new RowContent(slice, mIsHeader);
+        mHeaderActions = null;
+        mRowContent = new RowContent(getContext(), slice, mIsHeader);
         populateViews();
     }
 
@@ -144,11 +165,11 @@
      */
     @Override
     public void setSlice(Slice slice) {
-        mInSmallMode = true;
         mRowIndex = 0;
         mIsHeader = true;
-        ListContent lc = new ListContent(slice);
-        mRowContent = new RowContent(lc.getHeaderItem(), true /* isHeader */);
+        mHeaderActions = null;
+        ListContent lc = new ListContent(getContext(), slice);
+        mRowContent = new RowContent(getContext(), lc.getHeaderItem(), true /* isHeader */);
         populateViews();
     }
 
@@ -175,7 +196,7 @@
         mPrimaryText.setTextColor(mTitleColor);
         mPrimaryText.setVisibility(titleItem != null ? View.VISIBLE : View.GONE);
 
-        final SliceItem subTitle = mInSmallMode
+        final SliceItem subTitle = getMode() == MODE_SMALL
                 ? mRowContent.getSummaryItem()
                 : mRowContent.getSubtitleItem();
         if (subTitle != null) {
@@ -193,8 +214,29 @@
             return;
         }
 
-        mRowAction = mRowContent.getContentIntent();
-        ArrayList<SliceItem> endItems = mRowContent.getEndItems();
+        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);
@@ -203,15 +245,14 @@
 
         // If we're here we might be able to show end items
         int itemCount = 0;
-        // Prefer to show actions as end items if possible; fall back to the first format type.
-        String desiredFormat = mRowContent.endItemsContainAction()
-                ? FORMAT_ACTION : endItems.get(0).getFormat();
         boolean firstItemIsADefaultToggle = false;
         for (int i = 0; i < endItems.size(); i++) {
             final SliceItem endItem = endItems.get(i);
-            final String endFormat = endItem.getFormat();
+            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
+            if (itemCount < MAX_END_ITEMS
                     && (desiredFormat.equals(endFormat)
                     || FORMAT_TIMESTAMP.equals(endFormat))) {
                 final EventInfo info = new EventInfo(getMode(),
@@ -242,8 +283,9 @@
         } else {
             // If the only end item is an action, make the whole row clickable.
             if (mRowContent.endItemsContainAction() && itemCount == 1) {
-                if (!SUBTYPE_TOGGLE.equals(endItems.get(0).getSubType())) {
-                    mRowAction = endItems.get(0);
+                SliceItem unwrappedActionItem = endItems.get(0).getSlice().getItems().get(0);
+                if (!SUBTYPE_TOGGLE.equals(unwrappedActionItem.getSubType())) {
+                    mRowAction = new ActionContent(endItems.get(0));
                 }
                 setViewClickable(this, true);
             }
@@ -295,17 +337,11 @@
     /**
      * Add a toggle view to container.
      */
-    private void addToggle(final SliceItem toggleItem, int color, ViewGroup container) {
+    private void addToggle(final ActionContent actionContent, int color, ViewGroup container) {
         // Check if this is a custom toggle
-        Icon checkedIcon = null;
-        List<SliceItem> sliceItems = toggleItem.getSlice().getItems();
-        if (sliceItems.size() > 0) {
-            checkedIcon = FORMAT_IMAGE.equals(sliceItems.get(0).getFormat())
-                    ? sliceItems.get(0).getIcon()
-                    : null;
-        }
         final CompoundButton toggle;
-        if (checkedIcon != null) {
+        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?
@@ -323,12 +359,12 @@
             toggle = new Switch(getContext());
             container.addView(toggle);
         }
-        toggle.setChecked(SliceQuery.hasHints(toggleItem.getSlice(), HINT_SELECTED));
+        toggle.setChecked(actionContent.isChecked());
         toggle.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
             @Override
             public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                 try {
-                    PendingIntent pi = toggleItem.getAction();
+                    PendingIntent pi = actionContent.getActionItem().getAction();
                     Intent i = new Intent().putExtra(EXTRA_TOGGLE_STATE, isChecked);
                     pi.send(getContext(), 0, i, null, null);
                     if (mObserver != null) {
@@ -336,7 +372,7 @@
                                 EventInfo.ACTION_TYPE_TOGGLE,
                                 EventInfo.ROW_TYPE_LIST, mRowIndex);
                         info.state = isChecked ? EventInfo.STATE_ON : EventInfo.STATE_OFF;
-                        mObserver.onSliceAction(info, toggleItem);
+                        mObserver.onSliceAction(info, actionContent.getSliceItem());
                     }
                 } catch (CanceledException e) {
                     toggle.setSelected(!isChecked);
@@ -355,16 +391,25 @@
         SliceItem image = null;
         SliceItem action = null;
         SliceItem timeStamp = null;
+        ActionContent actionContent = null;
         ViewGroup container = isStart ? mStartContainer : mEndContainer;
-        if (FORMAT_ACTION.equals(sliceItem.getFormat())) {
-            if (SUBTYPE_TOGGLE.equals(sliceItem.getSubType())) {
-                addToggle(sliceItem, color, container);
+        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;
             }
-            image = SliceQuery.find(sliceItem.getSlice(), FORMAT_IMAGE);
-            timeStamp = SliceQuery.find(sliceItem.getSlice(), FORMAT_TIMESTAMP);
-            action = sliceItem;
-        } else if (FORMAT_IMAGE.equals(sliceItem.getFormat())) {
+            action = actionContent.getActionItem();
+            image = actionContent.getIconItem();
+        }
+        if (FORMAT_IMAGE.equals(sliceItem.getFormat())) {
             image = sliceItem;
         } else if (FORMAT_TIMESTAMP.equals(sliceItem.getFormat())) {
             timeStamp = sliceItem;
@@ -413,14 +458,14 @@
 
     @Override
     public void onClick(View view) {
-        if (mRowAction != null && FORMAT_ACTION.equals(mRowAction.getFormat())) {
+        if (mRowAction != null && mRowAction.getActionItem() != null && !mRowAction.isToggle()) {
             // Check for a row action
             try {
-                mRowAction.getAction().send();
+                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);
+                    mObserver.onSliceAction(info, mRowAction.getSliceItem());
                 }
             } catch (CanceledException e) {
                 Log.w(TAG, "PendingIntent for slice cannot be sent", e);
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
index a9faf86..9768894 100644
--- a/slices/view/src/main/java/androidx/app/slice/widget/SliceChildView.java
+++ b/slices/view/src/main/java/androidx/app/slice/widget/SliceChildView.java
@@ -25,6 +25,8 @@
 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;
@@ -37,6 +39,7 @@
 public abstract class SliceChildView extends FrameLayout {
 
     protected SliceView.OnSliceActionListener mObserver;
+    protected int mMode;
     protected int mTintColor = -1;
     protected int mTitleColor;
     protected int mSubtitleColor;
@@ -55,10 +58,35 @@
         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.
      */
-    public abstract int getMode();
+    @SliceView.SliceMode
+    public int getMode() {
+        return mMode;
+    }
+
+    /**
+     * @return the height of this view when displayed in {@link SliceView#MODE_SMALL}.
+     */
+    public int getSmallHeight() {
+        return 0;
+    }
+
+    /**
+     * @return the height of this view if it displayed all of its contents.
+     */
+    public int getActualHeight() {
+        return 0;
+    }
 
     /**
      * @param slice the slice to show in this view.
@@ -124,4 +152,11 @@
             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/SliceView.java b/slices/view/src/main/java/androidx/app/slice/widget/SliceView.java
index 3d8ceef..6e1f0c0 100644
--- a/slices/view/src/main/java/androidx/app/slice/widget/SliceView.java
+++ b/slices/view/src/main/java/androidx/app/slice/widget/SliceView.java
@@ -16,11 +16,9 @@
 
 package androidx.app.slice.widget;
 
-import static android.app.slice.Slice.HINT_ACTIONS;
 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 static android.app.slice.SliceItem.FORMAT_SLICE;
 
 import android.arch.lifecycle.Observer;
 import android.content.Context;
@@ -39,6 +37,7 @@
 
 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;
 
@@ -115,24 +114,22 @@
      */
     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 SliceChildView mCurrentView;
+    private int mMode = MODE_LARGE;
     private Slice mCurrentSlice;
-    private final ActionRow mActions;
-    private final int mShortcutSize;
-    private OnSliceActionListener mSliceObserver;
+    private SliceChildView mCurrentView;
+    private List<SliceItem> mActions;
+    private final ActionRow mActionRow;
 
-    private boolean mShowActions = true;
+    private boolean mShowActions = false;
     private boolean mIsScrollable = true;
 
+    private final int mShortcutSize;
+    private final int mMinLargeHeight;
+
     private AttributeSet mAttrs;
-    private int mThemeTintColor;
+    private int mThemeTintColor = -1;
+
+    private OnSliceActionListener mSliceObserver;
 
     public SliceView(Context context) {
         this(context, null);
@@ -156,47 +153,77 @@
         } finally {
             a.recycle();
         }
-        mActions = new ActionRow(getContext(), true);
-        mActions.setBackground(new ColorDrawable(0xffeeeeee));
+        // 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());
+        mCurrentView.setMode(getMode());
         addView(mCurrentView.getView(), getChildLp(mCurrentView.getView()));
-        addView(mActions, getChildLp(mActions));
+        addView(mActionRow, getChildLp(mActionRow));
         mShortcutSize = getContext().getResources()
                 .getDimensionPixelSize(R.dimen.abc_slice_shortcut_size);
+        mMinLargeHeight = getResources().getDimensionPixelSize(R.dimen.abc_slice_large_height);
+    }
+
+    private int getHeightForMode() {
+        int mode = getMode();
+        if (mode == MODE_SHORTCUT) {
+            return mShortcutSize;
+        }
+        return mode == MODE_LARGE
+                ? mCurrentView.getActualHeight()
+                : mCurrentView.getSmallHeight();
     }
 
     @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
+            // TODO: consider scaling the shortcut to fit if too small
             childWidth = mShortcutSize;
             width = mShortcutSize;
         }
+
+        final int actionHeight = mActionRow.getVisibility() != View.GONE
+                ? mActionRow.getMeasuredHeight()
+                : 0;
+        final int sliceHeight = getHeightForMode() + actionHeight;
+        final int heightAvailable = MeasureSpec.getSize(heightMeasureSpec);
+        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+        int height = heightAvailable;
+        if (heightAvailable >= sliceHeight) {
+            // Available space is larger than the slice
+            if (heightMode == MeasureSpec.AT_MOST || heightMode == MeasureSpec.UNSPECIFIED) {
+                height = sliceHeight;
+            }
+        } else {
+            // Not enough space available for slice in current mode
+            if (getMode() == MODE_LARGE && heightAvailable >= mMinLargeHeight + actionHeight) {
+                // It's just a slice with scrolling content; cap it to height available.
+                height = heightAvailable;
+            } else if (getMode() == MODE_SHORTCUT) {
+                // TODO: consider scaling the shortcut to fit if too small
+                height = mShortcutSize;
+            }
+        }
+        heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
+
+        // Measure the children without the padding
         final int left = getPaddingLeft();
         final int top = getPaddingTop();
         final int right = getPaddingRight();
         final int bot = getPaddingBottom();
-
-        // Measure the children without the padding
+        int childHeight = MeasureSpec.getSize(heightMeasureSpec);
         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 = mActions.getVisibility() != View.GONE
-                ? mActions.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);
+        setMeasuredDimension(width, heightMeasureSpec);
     }
 
     @Override
@@ -207,11 +234,11 @@
         final int right = getPaddingRight();
         final int bottom = getPaddingBottom();
         v.layout(left, top, left + v.getMeasuredWidth(), top + v.getMeasuredHeight());
-        if (mActions.getVisibility() != View.GONE) {
-            mActions.layout(left,
+        if (mActionRow.getVisibility() != View.GONE) {
+            mActionRow.layout(left,
                     top + v.getMeasuredHeight() + bottom,
-                    left + mActions.getMeasuredWidth() + right,
-                    top + v.getMeasuredHeight() + bottom + mActions.getMeasuredHeight());
+                    left + mActionRow.getMeasuredWidth() + right,
+                    top + v.getMeasuredHeight() + bottom + mActionRow.getMeasuredHeight());
         }
     }
 
@@ -227,16 +254,57 @@
      * content see {@link SliceLiveData}.
      */
     public void setSlice(@Nullable Slice slice) {
-        if (mCurrentSlice != null && slice != null
-                && !mCurrentSlice.getUri().equals(slice.getUri())) {
-            // New slice, reset view
-            mCurrentView.resetView();
+        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) {
@@ -280,6 +348,9 @@
         if (animate) {
             Log.e(TAG, "Animation not supported yet");
         }
+        if (mMode == mode) {
+            return;
+        }
         mMode = mode;
         reinflate();
     }
@@ -288,9 +359,6 @@
      * @return the mode this view is presenting in.
      */
     public @SliceMode int getMode() {
-        if (mMode == MODE_AUTO) {
-            return MODE_LARGE;
-        }
         return mMode;
     }
 
@@ -302,20 +370,24 @@
     @RestrictTo(RestrictTo.Scope.LIBRARY)
     public void setShowActionRow(boolean show) {
         mShowActions = show;
-        reinflate();
+        updateActions();
     }
 
-    private SliceChildView createView(int mode) {
+    /**
+     * @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:
-                // Check if it's horizontal and use a grid instead
-                if (SliceQuery.hasHints(mCurrentSlice, HINT_HORIZONTAL)) {
-                    return new GridRowView(getContext());
-                } else {
-                    return new RowView(getContext());
-                }
+                return isGrid ? new GridRowView(getContext()) : new RowView(getContext());
         }
         return new LargeTemplateView(getContext());
     }
@@ -325,47 +397,62 @@
             mCurrentView.resetView();
             return;
         }
+        ListContent lc = new ListContent(getContext(), 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 isSmallGridShowing = mCurrentView instanceof GridRowView;
-        boolean isGridSlice = SliceQuery.hasHints(mCurrentSlice, HINT_HORIZONTAL);
-        if (mMode == mCurrentView.getMode() && isGridSlice == isSmallGridShowing) {
-            mCurrentView.setSlice(mCurrentSlice);
-        } else {
+        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);
+            mCurrentView = createView(mode, isSmallGrid);
             if (mSliceObserver != null) {
                 mCurrentView.setSliceActionListener(mSliceObserver);
             }
             addView(mCurrentView.getView(), getChildLp(mCurrentView.getView()));
-            addView(mActions, getChildLp(mActions));
+            addView(mActionRow, getChildLp(mActionRow));
+            mCurrentView.setMode(mode);
         }
         // Scrolling
-        if (mode == MODE_LARGE) {
+        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
-        SliceItem actionRow = SliceQuery.find(mCurrentSlice, FORMAT_SLICE,
-                HINT_ACTIONS,
-                null);
-        List<SliceItem> items = mCurrentSlice.getItems();
-        if (items.size() > 1 || (items.size() != 0 && items.get(0) != actionRow)) {
-            mCurrentView.getView().setVisibility(View.VISIBLE);
-            mCurrentView.setSlice(mCurrentSlice);
-        } else {
-            mCurrentView.getView().setVisibility(View.GONE);
+        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;
         }
-        // Deal with actions
-        boolean showActions = mShowActions && actionRow != null
-                && mode != MODE_SHORTCUT;
-        if (showActions) {
-            mActions.setActions(actionRow, getTintColor());
-            mActions.setVisibility(View.VISIBLE);
-        } else {
-            mActions.setVisibility(View.GONE);
+
+        // 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);
         }
     }
 
@@ -386,7 +473,8 @@
         if (child instanceof ShortcutView) {
             return new LayoutParams(mShortcutSize, mShortcutSize);
         } else {
-            return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+            return new LayoutParams(LayoutParams.MATCH_PARENT,
+                    LayoutParams.MATCH_PARENT);
         }
     }
 
@@ -397,8 +485,6 @@
     @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:
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
deleted file mode 100644
index 7707dae..0000000
--- a/slices/view/src/main/res/layout-v21/abc_slice_small_template.xml
+++ /dev/null
@@ -1,89 +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.
-  -->
-<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
index 890f77d..e4cf7c5 100644
--- a/slices/view/src/main/res/layout/abc_slice_grid.xml
+++ b/slices/view/src/main/res/layout/abc_slice_grid.xml
@@ -17,8 +17,7 @@
 <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:layout_height="match_parent"
     android:gravity="center_vertical"
     android:background="?android:attr/activatedBackgroundIndicator"
     android:clipToPadding="false">
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
index b446ddd..0870465 100644
--- a/slices/view/src/main/res/layout/abc_slice_secondary_text.xml
+++ b/slices/view/src/main/res/layout/abc_slice_secondary_text.xml
@@ -23,4 +23,6 @@
         android:gravity="center"
         android:layout_height="wrap_content"
         android:padding="4dp"
-        android:layout_width="match_parent" />
+        android:layout_width="match_parent"
+        android:maxLines="1"
+        android:ellipsize="end"/>
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
index 2d5e913..4a47c06 100644
--- a/slices/view/src/main/res/layout/abc_slice_small_template.xml
+++ b/slices/view/src/main/res/layout/abc_slice_small_template.xml
@@ -17,11 +17,11 @@
 <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:layout_height="match_parent"
     android:gravity="center_vertical"
+    android:layout_gravity="center_vertical"
     android:background="?android:attr/activatedBackgroundIndicator"
+    android:orientation="horizontal"
     android:clipToPadding="false">
 
     <LinearLayout
@@ -34,8 +34,8 @@
 
     <LinearLayout
         android:id="@android:id/content"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
         android:layout_weight="1"
         android:gravity="center_vertical"
         android:orientation="vertical">
@@ -43,13 +43,13 @@
         <TextView android:id="@android:id/title"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:maxLines="2"/>
+            android:maxLines="1"/>
 
         <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" />
+            android:maxLines="1" />
 
         <SeekBar
             android:id="@+id/seek_bar"
diff --git a/slices/view/src/main/res/layout/abc_slice_title.xml b/slices/view/src/main/res/layout/abc_slice_title.xml
index e1bdf03..70a1400 100644
--- a/slices/view/src/main/res/layout/abc_slice_title.xml
+++ b/slices/view/src/main/res/layout/abc_slice_title.xml
@@ -23,4 +23,6 @@
         android:gravity="center"
         android:layout_height="wrap_content"
         android:padding="4dp"
-        android:layout_width="match_parent" />
+        android:layout_width="match_parent"
+        android:maxLines="1"
+        android:ellipsize="end"/>
diff --git a/slices/view/src/main/res/values-af/strings.xml b/slices/view/src/main/res/values-af/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-af/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-am/strings.xml b/slices/view/src/main/res/values-am/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-am/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-ar/strings.xml b/slices/view/src/main/res/values-ar/strings.xml
new file mode 100644
index 0000000..21aa8a4
--- /dev/null
+++ b/slices/view/src/main/res/values-ar/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"بالإضافة إلى <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-az/strings.xml b/slices/view/src/main/res/values-az/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-az/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-b+sr+Latn/strings.xml b/slices/view/src/main/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..ffd9b9b
--- /dev/null
+++ b/slices/view/src/main/res/values-b+sr+Latn/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"i još <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-be/strings.xml b/slices/view/src/main/res/values-be/strings.xml
new file mode 100644
index 0000000..df8e965
--- /dev/null
+++ b/slices/view/src/main/res/values-be/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"Яшчэ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-bg/strings.xml b/slices/view/src/main/res/values-bg/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-bg/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-bn/strings.xml b/slices/view/src/main/res/values-bn/strings.xml
new file mode 100644
index 0000000..8737d8c
--- /dev/null
+++ b/slices/view/src/main/res/values-bn/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>টি"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-bs/strings.xml b/slices/view/src/main/res/values-bs/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-bs/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-ca/strings.xml b/slices/view/src/main/res/values-ca/strings.xml
new file mode 100644
index 0000000..8ae6f78
--- /dev/null
+++ b/slices/view/src/main/res/values-ca/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"<xliff:g id="NUMBER">%1$d</xliff:g> més"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-cs/strings.xml b/slices/view/src/main/res/values-cs/strings.xml
new file mode 100644
index 0000000..1d39c0f
--- /dev/null
+++ b/slices/view/src/main/res/values-cs/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"a ještě <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-da/strings.xml b/slices/view/src/main/res/values-da/strings.xml
new file mode 100644
index 0000000..40de41d
--- /dev/null
+++ b/slices/view/src/main/res/values-da/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"<xliff:g id="NUMBER">%1$d</xliff:g> mere"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-de/strings.xml b/slices/view/src/main/res/values-de/strings.xml
new file mode 100644
index 0000000..9d9bede
--- /dev/null
+++ b/slices/view/src/main/res/values-de/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-el/strings.xml b/slices/view/src/main/res/values-el/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-el/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-en-rAU/strings.xml b/slices/view/src/main/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-en-rAU/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-en-rCA/strings.xml b/slices/view/src/main/res/values-en-rCA/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-en-rCA/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-en-rGB/strings.xml b/slices/view/src/main/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-en-rGB/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-en-rIN/strings.xml b/slices/view/src/main/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-en-rIN/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-en-rXC/strings.xml b/slices/view/src/main/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000..b793412
--- /dev/null
+++ b/slices/view/src/main/res/values-en-rXC/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‏‎‎‏‎‎‏‏‏‏‎‏‏‏‎‎‏‏‎‏‏‏‏‏‎‎‎‏‏‏‏‎‎‏‎‎‏‎‏‏‎‏‏‏‏‎‏‎‏‏‎‏‏‎‎+ ‎‏‎‎‏‏‎<xliff:g id="NUMBER">%1$d</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-es-rUS/strings.xml b/slices/view/src/main/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..a445505
--- /dev/null
+++ b/slices/view/src/main/res/values-es-rUS/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"<xliff:g id="NUMBER">%1$d</xliff:g> más"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-es/strings.xml b/slices/view/src/main/res/values-es/strings.xml
new file mode 100644
index 0000000..dcdd33e
--- /dev/null
+++ b/slices/view/src/main/res/values-es/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"<xliff:g id="NUMBER">%1$d</xliff:g> más"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-et/strings.xml b/slices/view/src/main/res/values-et/strings.xml
new file mode 100644
index 0000000..a1675ff
--- /dev/null
+++ b/slices/view/src/main/res/values-et/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"ja veel <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-eu/strings.xml b/slices/view/src/main/res/values-eu/strings.xml
new file mode 100644
index 0000000..1c79d4a
--- /dev/null
+++ b/slices/view/src/main/res/values-eu/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"Beste <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-fa/strings.xml b/slices/view/src/main/res/values-fa/strings.xml
new file mode 100644
index 0000000..2b2abd2
--- /dev/null
+++ b/slices/view/src/main/res/values-fa/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"‎+ <xliff:g id="NUMBER">%1$d</xliff:g>‎"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-fi/strings.xml b/slices/view/src/main/res/values-fi/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-fi/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-fr-rCA/strings.xml b/slices/view/src/main/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-fr-rCA/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-fr/strings.xml b/slices/view/src/main/res/values-fr/strings.xml
new file mode 100644
index 0000000..73685ce
--- /dev/null
+++ b/slices/view/src/main/res/values-fr/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"<xliff:g id="NUMBER">%1$d</xliff:g> autres"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-gl/strings.xml b/slices/view/src/main/res/values-gl/strings.xml
new file mode 100644
index 0000000..573eae9
--- /dev/null
+++ b/slices/view/src/main/res/values-gl/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"<xliff:g id="NUMBER">%1$d</xliff:g> máis"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-gu/strings.xml b/slices/view/src/main/res/values-gu/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-gu/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-hi/strings.xml b/slices/view/src/main/res/values-hi/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-hi/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-hr/strings.xml b/slices/view/src/main/res/values-hr/strings.xml
new file mode 100644
index 0000000..7ecedf6
--- /dev/null
+++ b/slices/view/src/main/res/values-hr/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"još <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-hu/strings.xml b/slices/view/src/main/res/values-hu/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-hu/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-hy/strings.xml b/slices/view/src/main/res/values-hy/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-hy/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-in/strings.xml b/slices/view/src/main/res/values-in/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-in/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-is/strings.xml b/slices/view/src/main/res/values-is/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-is/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-it/strings.xml b/slices/view/src/main/res/values-it/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-it/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-iw/strings.xml b/slices/view/src/main/res/values-iw/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-iw/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-ja/strings.xml b/slices/view/src/main/res/values-ja/strings.xml
new file mode 100644
index 0000000..ed51803
--- /dev/null
+++ b/slices/view/src/main/res/values-ja/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"他 <xliff:g id="NUMBER">%1$d</xliff:g> 件"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-ka/strings.xml b/slices/view/src/main/res/values-ka/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-ka/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-kk/strings.xml b/slices/view/src/main/res/values-kk/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-kk/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-km/strings.xml b/slices/view/src/main/res/values-km/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-km/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-kn/strings.xml b/slices/view/src/main/res/values-kn/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-kn/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-ko/strings.xml b/slices/view/src/main/res/values-ko/strings.xml
new file mode 100644
index 0000000..2dc0279
--- /dev/null
+++ b/slices/view/src/main/res/values-ko/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"<xliff:g id="NUMBER">%1$d</xliff:g>개 더보기"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-ky/strings.xml b/slices/view/src/main/res/values-ky/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-ky/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-lo/strings.xml b/slices/view/src/main/res/values-lo/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-lo/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-lt/strings.xml b/slices/view/src/main/res/values-lt/strings.xml
new file mode 100644
index 0000000..bb6bcb3
--- /dev/null
+++ b/slices/view/src/main/res/values-lt/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"Dar <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-lv/strings.xml b/slices/view/src/main/res/values-lv/strings.xml
new file mode 100644
index 0000000..79ccb99
--- /dev/null
+++ b/slices/view/src/main/res/values-lv/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"Vēl <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-mk/strings.xml b/slices/view/src/main/res/values-mk/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-mk/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-ml/strings.xml b/slices/view/src/main/res/values-ml/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-ml/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-mn/strings.xml b/slices/view/src/main/res/values-mn/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-mn/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-mr/strings.xml b/slices/view/src/main/res/values-mr/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-mr/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-ms/strings.xml b/slices/view/src/main/res/values-ms/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-ms/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-my/strings.xml b/slices/view/src/main/res/values-my/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-my/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-nb/strings.xml b/slices/view/src/main/res/values-nb/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-nb/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-ne/strings.xml b/slices/view/src/main/res/values-ne/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-ne/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-nl/strings.xml b/slices/view/src/main/res/values-nl/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-nl/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-pa/strings.xml b/slices/view/src/main/res/values-pa/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-pa/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-pl/strings.xml b/slices/view/src/main/res/values-pl/strings.xml
new file mode 100644
index 0000000..9d9bede
--- /dev/null
+++ b/slices/view/src/main/res/values-pl/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-pt-rBR/strings.xml b/slices/view/src/main/res/values-pt-rBR/strings.xml
new file mode 100644
index 0000000..629ba48
--- /dev/null
+++ b/slices/view/src/main/res/values-pt-rBR/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"Mais <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-pt-rPT/strings.xml b/slices/view/src/main/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-pt-rPT/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-pt/strings.xml b/slices/view/src/main/res/values-pt/strings.xml
new file mode 100644
index 0000000..629ba48
--- /dev/null
+++ b/slices/view/src/main/res/values-pt/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"Mais <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-ro/strings.xml b/slices/view/src/main/res/values-ro/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-ro/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-ru/strings.xml b/slices/view/src/main/res/values-ru/strings.xml
new file mode 100644
index 0000000..9d9bede
--- /dev/null
+++ b/slices/view/src/main/res/values-ru/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-si/strings.xml b/slices/view/src/main/res/values-si/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-si/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-sk/strings.xml b/slices/view/src/main/res/values-sk/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-sk/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-sl/strings.xml b/slices/view/src/main/res/values-sl/strings.xml
new file mode 100644
index 0000000..59bf101
--- /dev/null
+++ b/slices/view/src/main/res/values-sl/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"in še <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-sq/strings.xml b/slices/view/src/main/res/values-sq/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-sq/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-sr/strings.xml b/slices/view/src/main/res/values-sr/strings.xml
new file mode 100644
index 0000000..a66220a
--- /dev/null
+++ b/slices/view/src/main/res/values-sr/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"и још <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-sv/strings.xml b/slices/view/src/main/res/values-sv/strings.xml
new file mode 100644
index 0000000..cbcec4f
--- /dev/null
+++ b/slices/view/src/main/res/values-sv/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"<xliff:g id="NUMBER">%1$d</xliff:g> till"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-sw/strings.xml b/slices/view/src/main/res/values-sw/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-sw/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-ta/strings.xml b/slices/view/src/main/res/values-ta/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-ta/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-te/strings.xml b/slices/view/src/main/res/values-te/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-te/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-th/strings.xml b/slices/view/src/main/res/values-th/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-th/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-tl/strings.xml b/slices/view/src/main/res/values-tl/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-tl/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-tr/strings.xml b/slices/view/src/main/res/values-tr/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-tr/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-uk/strings.xml b/slices/view/src/main/res/values-uk/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-uk/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-ur/strings.xml b/slices/view/src/main/res/values-ur/strings.xml
new file mode 100644
index 0000000..ce427c0
--- /dev/null
+++ b/slices/view/src/main/res/values-ur/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"‎‎‎‎‎+ <xliff:g id="NUMBER">%1$d</xliff:g>‎‎"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-uz/strings.xml b/slices/view/src/main/res/values-uz/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-uz/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-vi/strings.xml b/slices/view/src/main/res/values-vi/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-vi/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-zh-rCN/strings.xml b/slices/view/src/main/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-zh-rCN/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-zh-rHK/strings.xml b/slices/view/src/main/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-zh-rHK/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-zh-rTW/strings.xml b/slices/view/src/main/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-zh-rTW/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values-zu/strings.xml b/slices/view/src/main/res/values-zu/strings.xml
new file mode 100644
index 0000000..ea5ab25
--- /dev/null
+++ b/slices/view/src/main/res/values-zu/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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+</resources>
diff --git a/slices/view/src/main/res/values/dimens.xml b/slices/view/src/main/res/values/dimens.xml
index ff2fb97..04d74f3 100644
--- a/slices/view/src/main/res/values/dimens.xml
+++ b/slices/view/src/main/res/values/dimens.xml
@@ -17,17 +17,18 @@
 
 <resources>
     <!-- General -->
-    <!-- Size of normal icons / images in a slice -->
+    <!-- Size of icons 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>
+    <!-- Size of small images in a slice -->
+    <dimen name="abc_slice_small_image_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 -->
+    <!-- Minimum height of a small template -->
+    <dimen name="abc_slice_small_height">48dp</dimen>
+    <!-- Minimum height of a large template -->
     <dimen name="abc_slice_large_height">240dp</dimen>
 
     <!-- Row view sizes-->
@@ -39,10 +40,22 @@
     <dimen name="abc_slice_row_active_input_height">120dp</dimen>
 
     <!-- Grid view sizes-->
-    <!-- Height of a grid row displaying only images -->
+    <!-- Height of a grid row displaying only text or only small images (but not both) -->
+    <dimen name="abc_slice_grid_min_height">60dp</dimen>
+    <!-- Height of a grid row displaying only large 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>
+    <!-- Height of a grid row showing one text item along with a large image -->
+    <dimen name="abc_slice_grid_image_text_height">120dp</dimen>
+    <!-- Height of a grid row showing two text items along with a large image -->
+    <dimen name="abc_slice_grid_max_height">140dp</dimen>
+    <!-- Height of a grid row showing 1-2 text items along with a small image -->
+    <dimen name="abc_slice_grid_small_image_text_height">120dp</dimen>
+    <!-- Gutter between cells in a grid row-->
+    <dimen name="abc_slice_grid_gutter">4dp</dimen>
+
+    <!-- Big picture -->
+    <!-- Min height of row showing a single large image -->
+    <dimen name="abc_slice_big_pic_min_height">120dp</dimen>
+    <!-- Max height of row showing a single large image -->
+    <dimen name="abc_slice_big_pic_max_height">140dp</dimen>
 </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/slidingpanelayout/src/main/java/android/support/v4/widget/SlidingPaneLayout.java b/slidingpanelayout/src/main/java/android/support/v4/widget/SlidingPaneLayout.java
new file mode 100644
index 0000000..4074ca3
--- /dev/null
+++ b/slidingpanelayout/src/main/java/android/support/v4/widget/SlidingPaneLayout.java
@@ -0,0 +1,1647 @@
+/*
+ * 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.
+ */
+
+package android.support.v4.widget;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.annotation.ColorInt;
+import android.support.annotation.DrawableRes;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.Px;
+import android.support.annotation.RequiresApi;
+import android.support.v4.content.ContextCompat;
+import android.support.v4.view.AbsSavedState;
+import android.support.v4.view.AccessibilityDelegateCompat;
+import android.support.v4.view.ViewCompat;
+import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.view.accessibility.AccessibilityEvent;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+
+/**
+ * SlidingPaneLayout provides a horizontal, multi-pane layout for use at the top level
+ * of a UI. A left (or first) pane is treated as a content list or browser, subordinate to a
+ * primary detail view for displaying content.
+ *
+ * <p>Child views may overlap if their combined width exceeds the available width
+ * in the SlidingPaneLayout. When this occurs the user may slide the topmost view out of the way
+ * by dragging it, or by navigating in the direction of the overlapped view using a keyboard.
+ * If the content of the dragged child view is itself horizontally scrollable, the user may
+ * grab it by the very edge.</p>
+ *
+ * <p>Thanks to this sliding behavior, SlidingPaneLayout may be suitable for creating layouts
+ * that can smoothly adapt across many different screen sizes, expanding out fully on larger
+ * screens and collapsing on smaller screens.</p>
+ *
+ * <p>SlidingPaneLayout is distinct from a navigation drawer as described in the design
+ * guide and should not be used in the same scenarios. SlidingPaneLayout should be thought
+ * of only as a way to allow a two-pane layout normally used on larger screens to adapt to smaller
+ * screens in a natural way. The interaction patterns expressed by SlidingPaneLayout imply
+ * a physicality and direct information hierarchy between panes that does not necessarily exist
+ * in a scenario where a navigation drawer should be used instead.</p>
+ *
+ * <p>Appropriate uses of SlidingPaneLayout include pairings of panes such as a contact list and
+ * subordinate interactions with those contacts, or an email thread list with the content pane
+ * displaying the contents of the selected thread. Inappropriate uses of SlidingPaneLayout include
+ * switching between disparate functions of your app, such as jumping from a social stream view
+ * to a view of your personal profile - cases such as this should use the navigation drawer
+ * pattern instead. ({@link DrawerLayout DrawerLayout} implements this pattern.)</p>
+ *
+ * <p>Like {@link android.widget.LinearLayout LinearLayout}, SlidingPaneLayout supports
+ * the use of the layout parameter <code>layout_weight</code> on child views to determine
+ * how to divide leftover space after measurement is complete. It is only relevant for width.
+ * When views do not overlap weight behaves as it does in a LinearLayout.</p>
+ *
+ * <p>When views do overlap, weight on a slideable pane indicates that the pane should be
+ * sized to fill all available space in the closed state. Weight on a pane that becomes covered
+ * indicates that the pane should be sized to fill all available space except a small minimum strip
+ * that the user may use to grab the slideable view and pull it back over into a closed state.</p>
+ */
+public class SlidingPaneLayout extends ViewGroup {
+    private static final String TAG = "SlidingPaneLayout";
+
+    /**
+     * Default size of the overhang for a pane in the open state.
+     * At least this much of a sliding pane will remain visible.
+     * This indicates that there is more content available and provides
+     * a "physical" edge to grab to pull it closed.
+     */
+    private static final int DEFAULT_OVERHANG_SIZE = 32; // dp;
+
+    /**
+     * If no fade color is given by default it will fade to 80% gray.
+     */
+    private static final int DEFAULT_FADE_COLOR = 0xcccccccc;
+
+    /**
+     * The fade color used for the sliding panel. 0 = no fading.
+     */
+    private int mSliderFadeColor = DEFAULT_FADE_COLOR;
+
+    /**
+     * Minimum velocity that will be detected as a fling
+     */
+    private static final int MIN_FLING_VELOCITY = 400; // dips per second
+
+    /**
+     * The fade color used for the panel covered by the slider. 0 = no fading.
+     */
+    private int mCoveredFadeColor;
+
+    /**
+     * Drawable used to draw the shadow between panes by default.
+     */
+    private Drawable mShadowDrawableLeft;
+
+    /**
+     * Drawable used to draw the shadow between panes to support RTL (right to left language).
+     */
+    private Drawable mShadowDrawableRight;
+
+    /**
+     * The size of the overhang in pixels.
+     * This is the minimum section of the sliding panel that will
+     * be visible in the open state to allow for a closing drag.
+     */
+    private final int mOverhangSize;
+
+    /**
+     * True if a panel can slide with the current measurements
+     */
+    private boolean mCanSlide;
+
+    /**
+     * The child view that can slide, if any.
+     */
+    View mSlideableView;
+
+    /**
+     * How far the panel is offset from its closed position.
+     * range [0, 1] where 0 = closed, 1 = open.
+     */
+    float mSlideOffset;
+
+    /**
+     * How far the non-sliding panel is parallaxed from its usual position when open.
+     * range [0, 1]
+     */
+    private float mParallaxOffset;
+
+    /**
+     * How far in pixels the slideable panel may move.
+     */
+    int mSlideRange;
+
+    /**
+     * A panel view is locked into internal scrolling or another condition that
+     * is preventing a drag.
+     */
+    boolean mIsUnableToDrag;
+
+    /**
+     * Distance in pixels to parallax the fixed pane by when fully closed
+     */
+    private int mParallaxBy;
+
+    private float mInitialMotionX;
+    private float mInitialMotionY;
+
+    private PanelSlideListener mPanelSlideListener;
+
+    final ViewDragHelper mDragHelper;
+
+    /**
+     * Stores whether or not the pane was open the last time it was slideable.
+     * If open/close operations are invoked this state is modified. Used by
+     * instance state save/restore.
+     */
+    boolean mPreservedOpenState;
+    private boolean mFirstLayout = true;
+
+    private final Rect mTmpRect = new Rect();
+
+    final ArrayList<DisableLayerRunnable> mPostedRunnables = new ArrayList<>();
+
+    static final SlidingPanelLayoutImpl IMPL;
+
+    static {
+        if (Build.VERSION.SDK_INT >= 17) {
+            IMPL = new SlidingPanelLayoutImplJBMR1();
+        } else if (Build.VERSION.SDK_INT >= 16) {
+            IMPL = new SlidingPanelLayoutImplJB();
+        } else {
+            IMPL = new SlidingPanelLayoutImplBase();
+        }
+    }
+
+    /**
+     * Listener for monitoring events about sliding panes.
+     */
+    public interface PanelSlideListener {
+        /**
+         * Called when a sliding pane's position changes.
+         * @param panel The child view that was moved
+         * @param slideOffset The new offset of this sliding pane within its range, from 0-1
+         */
+        void onPanelSlide(@NonNull View panel, float slideOffset);
+        /**
+         * Called when a sliding pane becomes slid completely open. The pane may or may not
+         * be interactive at this point depending on how much of the pane is visible.
+         * @param panel The child view that was slid to an open position, revealing other panes
+         */
+        void onPanelOpened(@NonNull View panel);
+
+        /**
+         * Called when a sliding pane becomes slid completely closed. The pane is now guaranteed
+         * to be interactive. It may now obscure other views in the layout.
+         * @param panel The child view that was slid to a closed position
+         */
+        void onPanelClosed(@NonNull View panel);
+    }
+
+    /**
+     * No-op stubs for {@link PanelSlideListener}. If you only want to implement a subset
+     * of the listener methods you can extend this instead of implement the full interface.
+     */
+    public static class SimplePanelSlideListener implements PanelSlideListener {
+        @Override
+        public void onPanelSlide(View panel, float slideOffset) {
+        }
+        @Override
+        public void onPanelOpened(View panel) {
+        }
+        @Override
+        public void onPanelClosed(View panel) {
+        }
+    }
+
+    public SlidingPaneLayout(@NonNull Context context) {
+        this(context, null);
+    }
+
+    public SlidingPaneLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public SlidingPaneLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+
+        final float density = context.getResources().getDisplayMetrics().density;
+        mOverhangSize = (int) (DEFAULT_OVERHANG_SIZE * density + 0.5f);
+
+        setWillNotDraw(false);
+
+        ViewCompat.setAccessibilityDelegate(this, new AccessibilityDelegate());
+        ViewCompat.setImportantForAccessibility(this, ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
+
+        mDragHelper = ViewDragHelper.create(this, 0.5f, new DragHelperCallback());
+        mDragHelper.setMinVelocity(MIN_FLING_VELOCITY * density);
+    }
+
+    /**
+     * Set a distance to parallax the lower pane by when the upper pane is in its
+     * fully closed state. The lower pane will scroll between this position and
+     * its fully open state.
+     *
+     * @param parallaxBy Distance to parallax by in pixels
+     */
+    public void setParallaxDistance(@Px int parallaxBy) {
+        mParallaxBy = parallaxBy;
+        requestLayout();
+    }
+
+    /**
+     * @return The distance the lower pane will parallax by when the upper pane is fully closed.
+     *
+     * @see #setParallaxDistance(int)
+     */
+    @Px
+    public int getParallaxDistance() {
+        return mParallaxBy;
+    }
+
+    /**
+     * Set the color used to fade the sliding pane out when it is slid most of the way offscreen.
+     *
+     * @param color An ARGB-packed color value
+     */
+    public void setSliderFadeColor(@ColorInt int color) {
+        mSliderFadeColor = color;
+    }
+
+    /**
+     * @return The ARGB-packed color value used to fade the sliding pane
+     */
+    @ColorInt
+    public int getSliderFadeColor() {
+        return mSliderFadeColor;
+    }
+
+    /**
+     * Set the color used to fade the pane covered by the sliding pane out when the pane
+     * will become fully covered in the closed state.
+     *
+     * @param color An ARGB-packed color value
+     */
+    public void setCoveredFadeColor(@ColorInt int color) {
+        mCoveredFadeColor = color;
+    }
+
+    /**
+     * @return The ARGB-packed color value used to fade the fixed pane
+     */
+    @ColorInt
+    public int getCoveredFadeColor() {
+        return mCoveredFadeColor;
+    }
+
+    public void setPanelSlideListener(@Nullable PanelSlideListener listener) {
+        mPanelSlideListener = listener;
+    }
+
+    void dispatchOnPanelSlide(View panel) {
+        if (mPanelSlideListener != null) {
+            mPanelSlideListener.onPanelSlide(panel, mSlideOffset);
+        }
+    }
+
+    void dispatchOnPanelOpened(View panel) {
+        if (mPanelSlideListener != null) {
+            mPanelSlideListener.onPanelOpened(panel);
+        }
+        sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+    }
+
+    void dispatchOnPanelClosed(View panel) {
+        if (mPanelSlideListener != null) {
+            mPanelSlideListener.onPanelClosed(panel);
+        }
+        sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+    }
+
+    void updateObscuredViewsVisibility(View panel) {
+        final boolean isLayoutRtl = isLayoutRtlSupport();
+        final int startBound = isLayoutRtl ? (getWidth() - getPaddingRight()) : getPaddingLeft();
+        final int endBound = isLayoutRtl ? getPaddingLeft() : (getWidth() - getPaddingRight());
+        final int topBound = getPaddingTop();
+        final int bottomBound = getHeight() - getPaddingBottom();
+        final int left;
+        final int right;
+        final int top;
+        final int bottom;
+        if (panel != null && viewIsOpaque(panel)) {
+            left = panel.getLeft();
+            right = panel.getRight();
+            top = panel.getTop();
+            bottom = panel.getBottom();
+        } else {
+            left = right = top = bottom = 0;
+        }
+
+        for (int i = 0, childCount = getChildCount(); i < childCount; i++) {
+            final View child = getChildAt(i);
+
+            if (child == panel) {
+                // There are still more children above the panel but they won't be affected.
+                break;
+            } else if (child.getVisibility() == GONE) {
+                continue;
+            }
+
+            final int clampedChildLeft = Math.max(
+                    (isLayoutRtl ? endBound : startBound), child.getLeft());
+            final int clampedChildTop = Math.max(topBound, child.getTop());
+            final int clampedChildRight = Math.min(
+                    (isLayoutRtl ? startBound : endBound), child.getRight());
+            final int clampedChildBottom = Math.min(bottomBound, child.getBottom());
+            final int vis;
+            if (clampedChildLeft >= left && clampedChildTop >= top
+                    && clampedChildRight <= right && clampedChildBottom <= bottom) {
+                vis = INVISIBLE;
+            } else {
+                vis = VISIBLE;
+            }
+            child.setVisibility(vis);
+        }
+    }
+
+    void setAllChildrenVisible() {
+        for (int i = 0, childCount = getChildCount(); i < childCount; i++) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() == INVISIBLE) {
+                child.setVisibility(VISIBLE);
+            }
+        }
+    }
+
+    private static boolean viewIsOpaque(View v) {
+        if (v.isOpaque()) {
+            return true;
+        }
+
+        // View#isOpaque didn't take all valid opaque scrollbar modes into account
+        // before API 18 (JB-MR2). On newer devices rely solely on isOpaque above and return false
+        // here. On older devices, check the view's background drawable directly as a fallback.
+        if (Build.VERSION.SDK_INT >= 18) {
+            return false;
+        }
+
+        final Drawable bg = v.getBackground();
+        if (bg != null) {
+            return bg.getOpacity() == PixelFormat.OPAQUE;
+        }
+        return false;
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        mFirstLayout = true;
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        mFirstLayout = true;
+
+        for (int i = 0, count = mPostedRunnables.size(); i < count; i++) {
+            final DisableLayerRunnable dlr = mPostedRunnables.get(i);
+            dlr.run();
+        }
+        mPostedRunnables.clear();
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
+
+        if (widthMode != 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;
+                }
+            } else {
+                throw new IllegalStateException("Width must have an exact value or MATCH_PARENT");
+            }
+        } else if (heightMode == MeasureSpec.UNSPECIFIED) {
+            if (isInEditMode()) {
+                // Don't crash the layout editor. Pick a magic number from thin air instead.
+                // TODO Better communication with tools of this bogus state.
+                // It will crash on a real device.
+                if (heightMode == MeasureSpec.UNSPECIFIED) {
+                    heightMode = MeasureSpec.AT_MOST;
+                    heightSize = 300;
+                }
+            } else {
+                throw new IllegalStateException("Height must not be UNSPECIFIED");
+            }
+        }
+
+        int layoutHeight = 0;
+        int maxLayoutHeight = 0;
+        switch (heightMode) {
+            case MeasureSpec.EXACTLY:
+                layoutHeight = maxLayoutHeight = heightSize - getPaddingTop() - getPaddingBottom();
+                break;
+            case MeasureSpec.AT_MOST:
+                maxLayoutHeight = heightSize - getPaddingTop() - getPaddingBottom();
+                break;
+        }
+
+        float weightSum = 0;
+        boolean canSlide = false;
+        final int widthAvailable = widthSize - getPaddingLeft() - getPaddingRight();
+        int widthRemaining = widthAvailable;
+        final int childCount = getChildCount();
+
+        if (childCount > 2) {
+            Log.e(TAG, "onMeasure: More than two child views are not supported.");
+        }
+
+        // We'll find the current one below.
+        mSlideableView = null;
+
+        // First pass. Measure based on child LayoutParams width/height.
+        // Weight will incur a second pass.
+        for (int i = 0; i < childCount; i++) {
+            final View child = getChildAt(i);
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+            if (child.getVisibility() == GONE) {
+                lp.dimWhenOffset = false;
+                continue;
+            }
+
+            if (lp.weight > 0) {
+                weightSum += lp.weight;
+
+                // If we have no width, weight is the only contributor to the final size.
+                // Measure this view on the weight pass only.
+                if (lp.width == 0) continue;
+            }
+
+            int childWidthSpec;
+            final int horizontalMargin = lp.leftMargin + lp.rightMargin;
+            if (lp.width == LayoutParams.WRAP_CONTENT) {
+                childWidthSpec = MeasureSpec.makeMeasureSpec(widthAvailable - horizontalMargin,
+                        MeasureSpec.AT_MOST);
+            } else if (lp.width == LayoutParams.MATCH_PARENT) {
+                childWidthSpec = MeasureSpec.makeMeasureSpec(widthAvailable - horizontalMargin,
+                        MeasureSpec.EXACTLY);
+            } else {
+                childWidthSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY);
+            }
+
+            int childHeightSpec;
+            if (lp.height == LayoutParams.WRAP_CONTENT) {
+                childHeightSpec = MeasureSpec.makeMeasureSpec(maxLayoutHeight, MeasureSpec.AT_MOST);
+            } else if (lp.height == LayoutParams.MATCH_PARENT) {
+                childHeightSpec = MeasureSpec.makeMeasureSpec(maxLayoutHeight, MeasureSpec.EXACTLY);
+            } else {
+                childHeightSpec = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY);
+            }
+
+            child.measure(childWidthSpec, childHeightSpec);
+            final int childWidth = child.getMeasuredWidth();
+            final int childHeight = child.getMeasuredHeight();
+
+            if (heightMode == MeasureSpec.AT_MOST && childHeight > layoutHeight) {
+                layoutHeight = Math.min(childHeight, maxLayoutHeight);
+            }
+
+            widthRemaining -= childWidth;
+            canSlide |= lp.slideable = widthRemaining < 0;
+            if (lp.slideable) {
+                mSlideableView = child;
+            }
+        }
+
+        // Resolve weight and make sure non-sliding panels are smaller than the full screen.
+        if (canSlide || weightSum > 0) {
+            final int fixedPanelWidthLimit = widthAvailable - mOverhangSize;
+
+            for (int i = 0; i < childCount; i++) {
+                final View child = getChildAt(i);
+
+                if (child.getVisibility() == GONE) {
+                    continue;
+                }
+
+                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+                if (child.getVisibility() == GONE) {
+                    continue;
+                }
+
+                final boolean skippedFirstPass = lp.width == 0 && lp.weight > 0;
+                final int measuredWidth = skippedFirstPass ? 0 : child.getMeasuredWidth();
+                if (canSlide && child != mSlideableView) {
+                    if (lp.width < 0 && (measuredWidth > fixedPanelWidthLimit || lp.weight > 0)) {
+                        // Fixed panels in a sliding configuration should
+                        // be clamped to the fixed panel limit.
+                        final int childHeightSpec;
+                        if (skippedFirstPass) {
+                            // Do initial height measurement if we skipped measuring this view
+                            // the first time around.
+                            if (lp.height == LayoutParams.WRAP_CONTENT) {
+                                childHeightSpec = MeasureSpec.makeMeasureSpec(maxLayoutHeight,
+                                        MeasureSpec.AT_MOST);
+                            } else if (lp.height == LayoutParams.MATCH_PARENT) {
+                                childHeightSpec = MeasureSpec.makeMeasureSpec(maxLayoutHeight,
+                                        MeasureSpec.EXACTLY);
+                            } else {
+                                childHeightSpec = MeasureSpec.makeMeasureSpec(lp.height,
+                                        MeasureSpec.EXACTLY);
+                            }
+                        } else {
+                            childHeightSpec = MeasureSpec.makeMeasureSpec(
+                                    child.getMeasuredHeight(), MeasureSpec.EXACTLY);
+                        }
+                        final int childWidthSpec = MeasureSpec.makeMeasureSpec(
+                                fixedPanelWidthLimit, MeasureSpec.EXACTLY);
+                        child.measure(childWidthSpec, childHeightSpec);
+                    }
+                } else if (lp.weight > 0) {
+                    int childHeightSpec;
+                    if (lp.width == 0) {
+                        // This was skipped the first time; figure out a real height spec.
+                        if (lp.height == LayoutParams.WRAP_CONTENT) {
+                            childHeightSpec = MeasureSpec.makeMeasureSpec(maxLayoutHeight,
+                                    MeasureSpec.AT_MOST);
+                        } else if (lp.height == LayoutParams.MATCH_PARENT) {
+                            childHeightSpec = MeasureSpec.makeMeasureSpec(maxLayoutHeight,
+                                    MeasureSpec.EXACTLY);
+                        } else {
+                            childHeightSpec = MeasureSpec.makeMeasureSpec(lp.height,
+                                    MeasureSpec.EXACTLY);
+                        }
+                    } else {
+                        childHeightSpec = MeasureSpec.makeMeasureSpec(
+                                child.getMeasuredHeight(), MeasureSpec.EXACTLY);
+                    }
+
+                    if (canSlide) {
+                        // Consume available space
+                        final int horizontalMargin = lp.leftMargin + lp.rightMargin;
+                        final int newWidth = widthAvailable - horizontalMargin;
+                        final int childWidthSpec = MeasureSpec.makeMeasureSpec(
+                                newWidth, MeasureSpec.EXACTLY);
+                        if (measuredWidth != newWidth) {
+                            child.measure(childWidthSpec, childHeightSpec);
+                        }
+                    } else {
+                        // Distribute the extra width proportionally similar to LinearLayout
+                        final int widthToDistribute = Math.max(0, widthRemaining);
+                        final int addedWidth = (int) (lp.weight * widthToDistribute / weightSum);
+                        final int childWidthSpec = MeasureSpec.makeMeasureSpec(
+                                measuredWidth + addedWidth, MeasureSpec.EXACTLY);
+                        child.measure(childWidthSpec, childHeightSpec);
+                    }
+                }
+            }
+        }
+
+        final int measuredWidth = widthSize;
+        final int measuredHeight = layoutHeight + getPaddingTop() + getPaddingBottom();
+
+        setMeasuredDimension(measuredWidth, measuredHeight);
+        mCanSlide = canSlide;
+
+        if (mDragHelper.getViewDragState() != ViewDragHelper.STATE_IDLE && !canSlide) {
+            // Cancel scrolling in progress, it's no longer relevant.
+            mDragHelper.abort();
+        }
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        final boolean isLayoutRtl = isLayoutRtlSupport();
+        if (isLayoutRtl) {
+            mDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_RIGHT);
+        } else {
+            mDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);
+        }
+        final int width = r - l;
+        final int paddingStart = isLayoutRtl ? getPaddingRight() : getPaddingLeft();
+        final int paddingEnd = isLayoutRtl ? getPaddingLeft() : getPaddingRight();
+        final int paddingTop = getPaddingTop();
+
+        final int childCount = getChildCount();
+        int xStart = paddingStart;
+        int nextXStart = xStart;
+
+        if (mFirstLayout) {
+            mSlideOffset = mCanSlide && mPreservedOpenState ? 1.f : 0.f;
+        }
+
+        for (int i = 0; i < childCount; i++) {
+            final View child = getChildAt(i);
+
+            if (child.getVisibility() == GONE) {
+                continue;
+            }
+
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+            final int childWidth = child.getMeasuredWidth();
+            int offset = 0;
+
+            if (lp.slideable) {
+                final int margin = lp.leftMargin + lp.rightMargin;
+                final int range = Math.min(nextXStart,
+                        width - paddingEnd - mOverhangSize) - xStart - margin;
+                mSlideRange = range;
+                final int lpMargin = isLayoutRtl ? lp.rightMargin : lp.leftMargin;
+                lp.dimWhenOffset = xStart + lpMargin + range + childWidth / 2 > width - paddingEnd;
+                final int pos = (int) (range * mSlideOffset);
+                xStart += pos + lpMargin;
+                mSlideOffset = (float) pos / mSlideRange;
+            } else if (mCanSlide && mParallaxBy != 0) {
+                offset = (int) ((1 - mSlideOffset) * mParallaxBy);
+                xStart = nextXStart;
+            } else {
+                xStart = nextXStart;
+            }
+
+            final int childRight;
+            final int childLeft;
+            if (isLayoutRtl) {
+                childRight = width - xStart + offset;
+                childLeft = childRight - childWidth;
+            } else {
+                childLeft = xStart - offset;
+                childRight = childLeft + childWidth;
+            }
+
+            final int childTop = paddingTop;
+            final int childBottom = childTop + child.getMeasuredHeight();
+            child.layout(childLeft, paddingTop, childRight, childBottom);
+
+            nextXStart += child.getWidth();
+        }
+
+        if (mFirstLayout) {
+            if (mCanSlide) {
+                if (mParallaxBy != 0) {
+                    parallaxOtherViews(mSlideOffset);
+                }
+                if (((LayoutParams) mSlideableView.getLayoutParams()).dimWhenOffset) {
+                    dimChildView(mSlideableView, mSlideOffset, mSliderFadeColor);
+                }
+            } else {
+                // Reset the dim level of all children; it's irrelevant when nothing moves.
+                for (int i = 0; i < childCount; i++) {
+                    dimChildView(getChildAt(i), 0, mSliderFadeColor);
+                }
+            }
+            updateObscuredViewsVisibility(mSlideableView);
+        }
+
+        mFirstLayout = false;
+    }
+
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        super.onSizeChanged(w, h, oldw, oldh);
+        // Recalculate sliding panes and their details
+        if (w != oldw) {
+            mFirstLayout = true;
+        }
+    }
+
+    @Override
+    public void requestChildFocus(View child, View focused) {
+        super.requestChildFocus(child, focused);
+        if (!isInTouchMode() && !mCanSlide) {
+            mPreservedOpenState = child == mSlideableView;
+        }
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        final int action = ev.getActionMasked();
+
+        // Preserve the open state based on the last view that was touched.
+        if (!mCanSlide && action == MotionEvent.ACTION_DOWN && getChildCount() > 1) {
+            // After the first things will be slideable.
+            final View secondChild = getChildAt(1);
+            if (secondChild != null) {
+                mPreservedOpenState = !mDragHelper.isViewUnder(secondChild,
+                        (int) ev.getX(), (int) ev.getY());
+            }
+        }
+
+        if (!mCanSlide || (mIsUnableToDrag && action != MotionEvent.ACTION_DOWN)) {
+            mDragHelper.cancel();
+            return super.onInterceptTouchEvent(ev);
+        }
+
+        if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
+            mDragHelper.cancel();
+            return false;
+        }
+
+        boolean interceptTap = false;
+
+        switch (action) {
+            case MotionEvent.ACTION_DOWN: {
+                mIsUnableToDrag = false;
+                final float x = ev.getX();
+                final float y = ev.getY();
+                mInitialMotionX = x;
+                mInitialMotionY = y;
+
+                if (mDragHelper.isViewUnder(mSlideableView, (int) x, (int) y)
+                        && isDimmed(mSlideableView)) {
+                    interceptTap = true;
+                }
+                break;
+            }
+
+            case MotionEvent.ACTION_MOVE: {
+                final float x = ev.getX();
+                final float y = ev.getY();
+                final float adx = Math.abs(x - mInitialMotionX);
+                final float ady = Math.abs(y - mInitialMotionY);
+                final int slop = mDragHelper.getTouchSlop();
+                if (adx > slop && ady > adx) {
+                    mDragHelper.cancel();
+                    mIsUnableToDrag = true;
+                    return false;
+                }
+            }
+        }
+
+        final boolean interceptForDrag = mDragHelper.shouldInterceptTouchEvent(ev);
+
+        return interceptForDrag || interceptTap;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        if (!mCanSlide) {
+            return super.onTouchEvent(ev);
+        }
+
+        mDragHelper.processTouchEvent(ev);
+
+        boolean wantTouchEvents = true;
+
+        switch (ev.getActionMasked()) {
+            case MotionEvent.ACTION_DOWN: {
+                final float x = ev.getX();
+                final float y = ev.getY();
+                mInitialMotionX = x;
+                mInitialMotionY = y;
+                break;
+            }
+
+            case MotionEvent.ACTION_UP: {
+                if (isDimmed(mSlideableView)) {
+                    final float x = ev.getX();
+                    final float y = ev.getY();
+                    final float dx = x - mInitialMotionX;
+                    final float dy = y - mInitialMotionY;
+                    final int slop = mDragHelper.getTouchSlop();
+                    if (dx * dx + dy * dy < slop * slop
+                            && mDragHelper.isViewUnder(mSlideableView, (int) x, (int) y)) {
+                        // Taps close a dimmed open pane.
+                        closePane(mSlideableView, 0);
+                        break;
+                    }
+                }
+                break;
+            }
+        }
+
+        return wantTouchEvents;
+    }
+
+    private boolean closePane(View pane, int initialVelocity) {
+        if (mFirstLayout || smoothSlideTo(0.f, initialVelocity)) {
+            mPreservedOpenState = false;
+            return true;
+        }
+        return false;
+    }
+
+    private boolean openPane(View pane, int initialVelocity) {
+        if (mFirstLayout || smoothSlideTo(1.f, initialVelocity)) {
+            mPreservedOpenState = true;
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * @deprecated Renamed to {@link #openPane()} - this method is going away soon!
+     */
+    @Deprecated
+    public void smoothSlideOpen() {
+        openPane();
+    }
+
+    /**
+     * Open the sliding pane if it is currently slideable. If first layout
+     * has already completed this will animate.
+     *
+     * @return true if the pane was slideable and is now open/in the process of opening
+     */
+    public boolean openPane() {
+        return openPane(mSlideableView, 0);
+    }
+
+    /**
+     * @deprecated Renamed to {@link #closePane()} - this method is going away soon!
+     */
+    @Deprecated
+    public void smoothSlideClosed() {
+        closePane();
+    }
+
+    /**
+     * Close the sliding pane if it is currently slideable. If first layout
+     * has already completed this will animate.
+     *
+     * @return true if the pane was slideable and is now closed/in the process of closing
+     */
+    public boolean closePane() {
+        return closePane(mSlideableView, 0);
+    }
+
+    /**
+     * Check if the layout is completely open. It can be open either because the slider
+     * itself is open revealing the left pane, or if all content fits without sliding.
+     *
+     * @return true if sliding panels are completely open
+     */
+    public boolean isOpen() {
+        return !mCanSlide || mSlideOffset == 1;
+    }
+
+    /**
+     * @return true if content in this layout can be slid open and closed
+     * @deprecated Renamed to {@link #isSlideable()} - this method is going away soon!
+     */
+    @Deprecated
+    public boolean canSlide() {
+        return mCanSlide;
+    }
+
+    /**
+     * Check if the content in this layout cannot fully fit side by side and therefore
+     * the content pane can be slid back and forth.
+     *
+     * @return true if content in this layout can be slid open and closed
+     */
+    public boolean isSlideable() {
+        return mCanSlide;
+    }
+
+    void onPanelDragged(int newLeft) {
+        if (mSlideableView == null) {
+            // This can happen if we're aborting motion during layout because everything now fits.
+            mSlideOffset = 0;
+            return;
+        }
+        final boolean isLayoutRtl = isLayoutRtlSupport();
+        final LayoutParams lp = (LayoutParams) mSlideableView.getLayoutParams();
+
+        int childWidth = mSlideableView.getWidth();
+        final int newStart = isLayoutRtl ? getWidth() - newLeft - childWidth : newLeft;
+
+        final int paddingStart = isLayoutRtl ? getPaddingRight() : getPaddingLeft();
+        final int lpMargin = isLayoutRtl ? lp.rightMargin : lp.leftMargin;
+        final int startBound = paddingStart + lpMargin;
+
+        mSlideOffset = (float) (newStart - startBound) / mSlideRange;
+
+        if (mParallaxBy != 0) {
+            parallaxOtherViews(mSlideOffset);
+        }
+
+        if (lp.dimWhenOffset) {
+            dimChildView(mSlideableView, mSlideOffset, mSliderFadeColor);
+        }
+        dispatchOnPanelSlide(mSlideableView);
+    }
+
+    private void dimChildView(View v, float mag, int fadeColor) {
+        final LayoutParams lp = (LayoutParams) v.getLayoutParams();
+
+        if (mag > 0 && fadeColor != 0) {
+            final int baseAlpha = (fadeColor & 0xff000000) >>> 24;
+            int imag = (int) (baseAlpha * mag);
+            int color = imag << 24 | (fadeColor & 0xffffff);
+            if (lp.dimPaint == null) {
+                lp.dimPaint = new Paint();
+            }
+            lp.dimPaint.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_OVER));
+            if (v.getLayerType() != View.LAYER_TYPE_HARDWARE) {
+                v.setLayerType(View.LAYER_TYPE_HARDWARE, lp.dimPaint);
+            }
+            invalidateChildRegion(v);
+        } else if (v.getLayerType() != View.LAYER_TYPE_NONE) {
+            if (lp.dimPaint != null) {
+                lp.dimPaint.setColorFilter(null);
+            }
+            final DisableLayerRunnable dlr = new DisableLayerRunnable(v);
+            mPostedRunnables.add(dlr);
+            ViewCompat.postOnAnimation(this, dlr);
+        }
+    }
+
+    @Override
+    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
+        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+        boolean result;
+        final int save = canvas.save();
+
+        if (mCanSlide && !lp.slideable && mSlideableView != null) {
+            // Clip against the slider; no sense drawing what will immediately be covered.
+            canvas.getClipBounds(mTmpRect);
+            if (isLayoutRtlSupport()) {
+                mTmpRect.left = Math.max(mTmpRect.left, mSlideableView.getRight());
+            } else {
+                mTmpRect.right = Math.min(mTmpRect.right, mSlideableView.getLeft());
+            }
+            canvas.clipRect(mTmpRect);
+        }
+
+        result = super.drawChild(canvas, child, drawingTime);
+
+        canvas.restoreToCount(save);
+
+        return result;
+    }
+
+    void invalidateChildRegion(View v) {
+        IMPL.invalidateChildRegion(this, v);
+    }
+
+    /**
+     * Smoothly animate mDraggingPane to the target X position within its range.
+     *
+     * @param slideOffset position to animate to
+     * @param velocity initial velocity in case of fling, or 0.
+     */
+    boolean smoothSlideTo(float slideOffset, int velocity) {
+        if (!mCanSlide) {
+            // Nothing to do.
+            return false;
+        }
+
+        final boolean isLayoutRtl = isLayoutRtlSupport();
+        final LayoutParams lp = (LayoutParams) mSlideableView.getLayoutParams();
+
+        int x;
+        if (isLayoutRtl) {
+            int startBound = getPaddingRight() + lp.rightMargin;
+            int childWidth = mSlideableView.getWidth();
+            x = (int) (getWidth() - (startBound + slideOffset * mSlideRange + childWidth));
+        } else {
+            int startBound = getPaddingLeft() + lp.leftMargin;
+            x = (int) (startBound + slideOffset * mSlideRange);
+        }
+
+        if (mDragHelper.smoothSlideViewTo(mSlideableView, x, mSlideableView.getTop())) {
+            setAllChildrenVisible();
+            ViewCompat.postInvalidateOnAnimation(this);
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public void computeScroll() {
+        if (mDragHelper.continueSettling(true)) {
+            if (!mCanSlide) {
+                mDragHelper.abort();
+                return;
+            }
+
+            ViewCompat.postInvalidateOnAnimation(this);
+        }
+    }
+
+    /**
+     * @deprecated Renamed to {@link #setShadowDrawableLeft(Drawable d)} to support LTR (left to
+     * right language) and {@link #setShadowDrawableRight(Drawable d)} to support RTL (right to left
+     * language) during opening/closing.
+     *
+     * @param d drawable to use as a shadow
+     */
+    @Deprecated
+    public void setShadowDrawable(Drawable d) {
+        setShadowDrawableLeft(d);
+    }
+
+    /**
+     * Set a drawable to use as a shadow cast by the right pane onto the left pane
+     * during opening/closing.
+     *
+     * @param d drawable to use as a shadow
+     */
+    public void setShadowDrawableLeft(@Nullable Drawable d) {
+        mShadowDrawableLeft = d;
+    }
+
+    /**
+     * Set a drawable to use as a shadow cast by the left pane onto the right pane
+     * during opening/closing to support right to left language.
+     *
+     * @param d drawable to use as a shadow
+     */
+    public void setShadowDrawableRight(@Nullable Drawable d) {
+        mShadowDrawableRight = d;
+    }
+
+    /**
+     * Set a drawable to use as a shadow cast by the right pane onto the left pane
+     * during opening/closing.
+     *
+     * @param resId Resource ID of a drawable to use
+     * @deprecated Renamed to {@link #setShadowResourceLeft(int)} to support LTR (left to
+     * right language) and {@link #setShadowResourceRight(int)} to support RTL (right to left
+     * language) during opening/closing.
+     */
+    @Deprecated
+    public void setShadowResource(@DrawableRes int resId) {
+        setShadowDrawable(getResources().getDrawable(resId));
+    }
+
+    /**
+     * Set a drawable to use as a shadow cast by the right pane onto the left pane
+     * during opening/closing.
+     *
+     * @param resId Resource ID of a drawable to use
+     */
+    public void setShadowResourceLeft(int resId) {
+        setShadowDrawableLeft(ContextCompat.getDrawable(getContext(), resId));
+    }
+
+    /**
+     * Set a drawable to use as a shadow cast by the left pane onto the right pane
+     * during opening/closing to support right to left language.
+     *
+     * @param resId Resource ID of a drawable to use
+     */
+    public void setShadowResourceRight(int resId) {
+        setShadowDrawableRight(ContextCompat.getDrawable(getContext(), resId));
+    }
+
+    @Override
+    public void draw(Canvas c) {
+        super.draw(c);
+        final boolean isLayoutRtl = isLayoutRtlSupport();
+        Drawable shadowDrawable;
+        if (isLayoutRtl) {
+            shadowDrawable = mShadowDrawableRight;
+        } else {
+            shadowDrawable = mShadowDrawableLeft;
+        }
+
+        final View shadowView = getChildCount() > 1 ? getChildAt(1) : null;
+        if (shadowView == null || shadowDrawable == null) {
+            // No need to draw a shadow if we don't have one.
+            return;
+        }
+
+        final int top = shadowView.getTop();
+        final int bottom = shadowView.getBottom();
+
+        final int shadowWidth = shadowDrawable.getIntrinsicWidth();
+        final int left;
+        final int right;
+        if (isLayoutRtlSupport()) {
+            left = shadowView.getRight();
+            right = left + shadowWidth;
+        } else {
+            right = shadowView.getLeft();
+            left = right - shadowWidth;
+        }
+
+        shadowDrawable.setBounds(left, top, right, bottom);
+        shadowDrawable.draw(c);
+    }
+
+    private void parallaxOtherViews(float slideOffset) {
+        final boolean isLayoutRtl = isLayoutRtlSupport();
+        final LayoutParams slideLp = (LayoutParams) mSlideableView.getLayoutParams();
+        final boolean dimViews = slideLp.dimWhenOffset
+                && (isLayoutRtl ? slideLp.rightMargin : slideLp.leftMargin) <= 0;
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final View v = getChildAt(i);
+            if (v == mSlideableView) continue;
+
+            final int oldOffset = (int) ((1 - mParallaxOffset) * mParallaxBy);
+            mParallaxOffset = slideOffset;
+            final int newOffset = (int) ((1 - slideOffset) * mParallaxBy);
+            final int dx = oldOffset - newOffset;
+
+            v.offsetLeftAndRight(isLayoutRtl ? -dx : dx);
+
+            if (dimViews) {
+                dimChildView(v, isLayoutRtl ? mParallaxOffset - 1
+                        : 1 - mParallaxOffset, mCoveredFadeColor);
+            }
+        }
+    }
+
+    /**
+     * Tests scrollability within child views of v given a delta of dx.
+     *
+     * @param v View to test for horizontal scrollability
+     * @param checkV Whether the view v passed should itself be checked for scrollability (true),
+     *               or just its children (false).
+     * @param dx Delta scrolled in pixels
+     * @param x X coordinate of the active touch point
+     * @param y Y coordinate of the active touch point
+     * @return true if child views of v can be scrolled by delta of dx.
+     */
+    protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
+        if (v instanceof ViewGroup) {
+            final ViewGroup group = (ViewGroup) v;
+            final int scrollX = v.getScrollX();
+            final int scrollY = v.getScrollY();
+            final int count = group.getChildCount();
+            // Count backwards - let topmost views consume scroll distance first.
+            for (int i = count - 1; i >= 0; i--) {
+                // TODO: Add versioned support here for transformed views.
+                // This will not work for transformed views in Honeycomb+
+                final View child = group.getChildAt(i);
+                if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight()
+                        && y + scrollY >= child.getTop() && y + scrollY < child.getBottom()
+                        && canScroll(child, true, dx, x + scrollX - child.getLeft(),
+                                y + scrollY - child.getTop())) {
+                    return true;
+                }
+            }
+        }
+
+        return checkV && v.canScrollHorizontally((isLayoutRtlSupport() ? dx : -dx));
+    }
+
+    boolean isDimmed(View child) {
+        if (child == null) {
+            return false;
+        }
+        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+        return mCanSlide && lp.dimWhenOffset && mSlideOffset > 0;
+    }
+
+    @Override
+    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
+        return new LayoutParams();
+    }
+
+    @Override
+    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
+        return p instanceof 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
+    protected Parcelable onSaveInstanceState() {
+        Parcelable superState = super.onSaveInstanceState();
+
+        SavedState ss = new SavedState(superState);
+        ss.isOpen = isSlideable() ? isOpen() : mPreservedOpenState;
+
+        return ss;
+    }
+
+    @Override
+    protected void onRestoreInstanceState(Parcelable state) {
+        if (!(state instanceof SavedState)) {
+            super.onRestoreInstanceState(state);
+            return;
+        }
+
+        SavedState ss = (SavedState) state;
+        super.onRestoreInstanceState(ss.getSuperState());
+
+        if (ss.isOpen) {
+            openPane();
+        } else {
+            closePane();
+        }
+        mPreservedOpenState = ss.isOpen;
+    }
+
+    private class DragHelperCallback extends ViewDragHelper.Callback {
+
+        DragHelperCallback() {
+        }
+
+        @Override
+        public boolean tryCaptureView(View child, int pointerId) {
+            if (mIsUnableToDrag) {
+                return false;
+            }
+
+            return ((LayoutParams) child.getLayoutParams()).slideable;
+        }
+
+        @Override
+        public void onViewDragStateChanged(int state) {
+            if (mDragHelper.getViewDragState() == ViewDragHelper.STATE_IDLE) {
+                if (mSlideOffset == 0) {
+                    updateObscuredViewsVisibility(mSlideableView);
+                    dispatchOnPanelClosed(mSlideableView);
+                    mPreservedOpenState = false;
+                } else {
+                    dispatchOnPanelOpened(mSlideableView);
+                    mPreservedOpenState = true;
+                }
+            }
+        }
+
+        @Override
+        public void onViewCaptured(View capturedChild, int activePointerId) {
+            // Make all child views visible in preparation for sliding things around
+            setAllChildrenVisible();
+        }
+
+        @Override
+        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
+            onPanelDragged(left);
+            invalidate();
+        }
+
+        @Override
+        public void onViewReleased(View releasedChild, float xvel, float yvel) {
+            final LayoutParams lp = (LayoutParams) releasedChild.getLayoutParams();
+
+            int left;
+            if (isLayoutRtlSupport()) {
+                int startToRight =  getPaddingRight() + lp.rightMargin;
+                if (xvel < 0 || (xvel == 0 && mSlideOffset > 0.5f)) {
+                    startToRight += mSlideRange;
+                }
+                int childWidth = mSlideableView.getWidth();
+                left = getWidth() - startToRight - childWidth;
+            } else {
+                left = getPaddingLeft() + lp.leftMargin;
+                if (xvel > 0 || (xvel == 0 && mSlideOffset > 0.5f)) {
+                    left += mSlideRange;
+                }
+            }
+            mDragHelper.settleCapturedViewAt(left, releasedChild.getTop());
+            invalidate();
+        }
+
+        @Override
+        public int getViewHorizontalDragRange(View child) {
+            return mSlideRange;
+        }
+
+        @Override
+        public int clampViewPositionHorizontal(View child, int left, int dx) {
+            final LayoutParams lp = (LayoutParams) mSlideableView.getLayoutParams();
+
+            final int newLeft;
+            if (isLayoutRtlSupport()) {
+                int startBound = getWidth()
+                        - (getPaddingRight() + lp.rightMargin + mSlideableView.getWidth());
+                int endBound =  startBound - mSlideRange;
+                newLeft = Math.max(Math.min(left, startBound), endBound);
+            } else {
+                int startBound = getPaddingLeft() + lp.leftMargin;
+                int endBound = startBound + mSlideRange;
+                newLeft = Math.min(Math.max(left, startBound), endBound);
+            }
+            return newLeft;
+        }
+
+        @Override
+        public int clampViewPositionVertical(View child, int top, int dy) {
+            // Make sure we never move views vertically.
+            // This could happen if the child has less height than its parent.
+            return child.getTop();
+        }
+
+        @Override
+        public void onEdgeDragStarted(int edgeFlags, int pointerId) {
+            mDragHelper.captureChildView(mSlideableView, pointerId);
+        }
+    }
+
+    public static class LayoutParams extends ViewGroup.MarginLayoutParams {
+        private static final int[] ATTRS = new int[] {
+            android.R.attr.layout_weight
+        };
+
+        /**
+         * The weighted proportion of how much of the leftover space
+         * this child should consume after measurement.
+         */
+        public float weight = 0;
+
+        /**
+         * True if this pane is the slideable pane in the layout.
+         */
+        boolean slideable;
+
+        /**
+         * True if this view should be drawn dimmed
+         * when it's been offset from its default position.
+         */
+        boolean dimWhenOffset;
+
+        Paint dimPaint;
+
+        public LayoutParams() {
+            super(MATCH_PARENT, MATCH_PARENT);
+        }
+
+        public LayoutParams(int width, int height) {
+            super(width, height);
+        }
+
+        public LayoutParams(@NonNull android.view.ViewGroup.LayoutParams source) {
+            super(source);
+        }
+
+        public LayoutParams(@NonNull MarginLayoutParams source) {
+            super(source);
+        }
+
+        public LayoutParams(@NonNull LayoutParams source) {
+            super(source);
+            this.weight = source.weight;
+        }
+
+        public LayoutParams(@NonNull Context c, @Nullable AttributeSet attrs) {
+            super(c, attrs);
+
+            final TypedArray a = c.obtainStyledAttributes(attrs, ATTRS);
+            this.weight = a.getFloat(0, 0);
+            a.recycle();
+        }
+
+    }
+
+    static class SavedState extends AbsSavedState {
+        boolean isOpen;
+
+        SavedState(Parcelable superState) {
+            super(superState);
+        }
+
+        SavedState(Parcel in, ClassLoader loader) {
+            super(in, loader);
+            isOpen = in.readInt() != 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel out, int flags) {
+            super.writeToParcel(out, flags);
+            out.writeInt(isOpen ? 1 : 0);
+        }
+
+        public static final Creator<SavedState> CREATOR = new ClassLoaderCreator<SavedState>() {
+            @Override
+            public SavedState createFromParcel(Parcel in, ClassLoader loader) {
+                return new SavedState(in, null);
+            }
+
+            @Override
+            public SavedState createFromParcel(Parcel in) {
+                return new SavedState(in, null);
+            }
+
+            @Override
+            public SavedState[] newArray(int size) {
+                return new SavedState[size];
+            }
+        };
+    }
+
+    interface SlidingPanelLayoutImpl {
+        void invalidateChildRegion(SlidingPaneLayout parent, View child);
+    }
+
+    static class SlidingPanelLayoutImplBase implements SlidingPanelLayoutImpl {
+        @Override
+        public void invalidateChildRegion(SlidingPaneLayout parent, View child) {
+            ViewCompat.postInvalidateOnAnimation(parent, child.getLeft(), child.getTop(),
+                    child.getRight(), child.getBottom());
+        }
+    }
+
+    @RequiresApi(16)
+    static class SlidingPanelLayoutImplJB extends SlidingPanelLayoutImplBase {
+        /*
+         * Private API hacks! Nasty! Bad!
+         *
+         * In Jellybean, some optimizations in the hardware UI renderer
+         * prevent a changed Paint on a View using a hardware layer from having
+         * the intended effect. This twiddles some internal bits on the view to force
+         * it to recreate the display list.
+         */
+        private Method mGetDisplayList;
+        private Field mRecreateDisplayList;
+
+        SlidingPanelLayoutImplJB() {
+            try {
+                mGetDisplayList = View.class.getDeclaredMethod("getDisplayList", (Class[]) null);
+            } catch (NoSuchMethodException e) {
+                Log.e(TAG, "Couldn't fetch getDisplayList method; dimming won't work right.", e);
+            }
+            try {
+                mRecreateDisplayList = View.class.getDeclaredField("mRecreateDisplayList");
+                mRecreateDisplayList.setAccessible(true);
+            } catch (NoSuchFieldException e) {
+                Log.e(TAG, "Couldn't fetch mRecreateDisplayList field; dimming will be slow.", e);
+            }
+        }
+
+        @Override
+        public void invalidateChildRegion(SlidingPaneLayout parent, View child) {
+            if (mGetDisplayList != null && mRecreateDisplayList != null) {
+                try {
+                    mRecreateDisplayList.setBoolean(child, true);
+                    mGetDisplayList.invoke(child, (Object[]) null);
+                } catch (Exception e) {
+                    Log.e(TAG, "Error refreshing display list state", e);
+                }
+            } else {
+                // Slow path. REALLY slow path. Let's hope we don't get here.
+                child.invalidate();
+                return;
+            }
+            super.invalidateChildRegion(parent, child);
+        }
+    }
+
+    @RequiresApi(17)
+    static class SlidingPanelLayoutImplJBMR1 extends SlidingPanelLayoutImplBase {
+        @Override
+        public void invalidateChildRegion(SlidingPaneLayout parent, View child) {
+            ViewCompat.setLayerPaint(child, ((LayoutParams) child.getLayoutParams()).dimPaint);
+        }
+    }
+
+    class AccessibilityDelegate extends AccessibilityDelegateCompat {
+        private final Rect mTmpRect = new Rect();
+
+        @Override
+        public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
+            final AccessibilityNodeInfoCompat superNode = AccessibilityNodeInfoCompat.obtain(info);
+            super.onInitializeAccessibilityNodeInfo(host, superNode);
+            copyNodeInfoNoChildren(info, superNode);
+            superNode.recycle();
+
+            info.setClassName(SlidingPaneLayout.class.getName());
+            info.setSource(host);
+
+            final ViewParent parent = ViewCompat.getParentForAccessibility(host);
+            if (parent instanceof View) {
+                info.setParent((View) parent);
+            }
+
+            // This is a best-approximation of addChildrenForAccessibility()
+            // that accounts for filtering.
+            final int childCount = getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                final View child = getChildAt(i);
+                if (!filter(child) && (child.getVisibility() == View.VISIBLE)) {
+                    // Force importance to "yes" since we can't read the value.
+                    ViewCompat.setImportantForAccessibility(
+                            child, ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
+                    info.addChild(child);
+                }
+            }
+        }
+
+        @Override
+        public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
+            super.onInitializeAccessibilityEvent(host, event);
+
+            event.setClassName(SlidingPaneLayout.class.getName());
+        }
+
+        @Override
+        public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child,
+                AccessibilityEvent event) {
+            if (!filter(child)) {
+                return super.onRequestSendAccessibilityEvent(host, child, event);
+            }
+            return false;
+        }
+
+        public boolean filter(View child) {
+            return isDimmed(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());
+
+            dest.setMovementGranularities(src.getMovementGranularities());
+        }
+    }
+
+    private class DisableLayerRunnable implements Runnable {
+        final View mChildView;
+
+        DisableLayerRunnable(View childView) {
+            mChildView = childView;
+        }
+
+        @Override
+        public void run() {
+            if (mChildView.getParent() == SlidingPaneLayout.this) {
+                mChildView.setLayerType(View.LAYER_TYPE_NONE, null);
+                invalidateChildRegion(mChildView);
+            }
+            mPostedRunnables.remove(this);
+        }
+    }
+
+    boolean isLayoutRtlSupport() {
+        return ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_RTL;
+    }
+}
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/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/androidTest/java/android/support/transition/ExplodeTest.java b/transition/src/androidTest/java/android/support/transition/ExplodeTest.java
index b421537..f5578e9 100644
--- a/transition/src/androidTest/java/android/support/transition/ExplodeTest.java
+++ b/transition/src/androidTest/java/android/support/transition/ExplodeTest.java
@@ -16,8 +16,11 @@
 
 package android.support.transition;
 
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.Matchers.greaterThan;
+import static org.hamcrest.Matchers.lessThan;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertThat;
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
@@ -70,8 +73,8 @@
         verifyTranslation(greenSquare, false, true);
         verifyTranslation(blueSquare, false, false);
         verifyTranslation(yellowSquare, true, false);
-        assertTrue(redStartX > redSquare.getTranslationX()); // moving left
-        assertTrue(redStartY > redSquare.getTranslationY()); // moving up
+        assertThat(redStartX, is(greaterThan(redSquare.getTranslationX()))); // moving left
+        assertThat(redStartY, is(greaterThan(redSquare.getTranslationY()))); // moving up
         waitForEnd();
 
         verifyNoTranslation(redSquare);
@@ -127,8 +130,8 @@
         verifyTranslation(greenSquare, false, true);
         verifyTranslation(blueSquare, false, false);
         verifyTranslation(yellowSquare, true, false);
-        assertTrue(redStartX < redSquare.getTranslationX()); // moving right
-        assertTrue(redStartY < redSquare.getTranslationY()); // moving down
+        assertThat(redStartX, is(lessThan(redSquare.getTranslationX()))); // moving right
+        assertThat(redStartY, is(lessThan(redSquare.getTranslationY()))); // moving down
         waitForEnd();
 
         verifyNoTranslation(redSquare);
@@ -146,15 +149,15 @@
         float translationY = view.getTranslationY();
 
         if (goLeft) {
-            assertTrue(translationX < 0);
+            assertThat(translationX, is(lessThan(0.f)));
         } else {
-            assertTrue(translationX > 0);
+            assertThat(translationX, is(greaterThan(0.f)));
         }
 
         if (goUp) {
-            assertTrue(translationY < 0);
+            assertThat(translationY, is(lessThan(0.f)));
         } else {
-            assertTrue(translationY > 0);
+            assertThat(translationY, is(greaterThan(0.f)));
         }
     }
 
diff --git a/transition/src/androidTest/java/android/support/transition/FadeTest.java b/transition/src/androidTest/java/android/support/transition/FadeTest.java
index 3b171e2..80d1547 100644
--- a/transition/src/androidTest/java/android/support/transition/FadeTest.java
+++ b/transition/src/androidTest/java/android/support/transition/FadeTest.java
@@ -138,7 +138,7 @@
         verify(listenerOut, timeout(3000)).onTransitionPause(any(Transition.class));
         verify(listenerIn, timeout(3000)).onTransitionStart(any(Transition.class));
         assertThat(valuesOut[1], allOf(greaterThan(0f), lessThan(1f)));
-        if (Build.VERSION.SDK_INT >= 19) {
+        if (Build.VERSION.SDK_INT >= 19 && fadeOut.mInitialAlpha >= 0) {
             // These won't match on API levels 18 and below due to lack of Animator pause.
             assertEquals(valuesOut[1], valuesIn[0], 0.01f);
         }
@@ -174,7 +174,7 @@
         verify(listenerIn, timeout(3000)).onTransitionPause(any(Transition.class));
         verify(listenerOut, timeout(3000)).onTransitionStart(any(Transition.class));
         assertThat(valuesIn[1], allOf(greaterThan(0f), lessThan(1f)));
-        if (Build.VERSION.SDK_INT >= 19) {
+        if (Build.VERSION.SDK_INT >= 19 && fadeIn.mInitialAlpha >= 0) {
             // These won't match on API levels 18 and below due to lack of Animator pause.
             assertEquals(valuesIn[1], valuesOut[0], 0.01f);
         }
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/java/android/support/media/tv/BasePreviewProgram.java b/tv-provider/src/main/java/android/support/media/tv/BasePreviewProgram.java
index 816b1a1..479471e 100644
--- a/tv-provider/src/main/java/android/support/media/tv/BasePreviewProgram.java
+++ b/tv-provider/src/main/java/android/support/media/tv/BasePreviewProgram.java
@@ -143,7 +143,7 @@
 
     /**
      * @return The internal provider ID for the program.
-     * @see PreviewPrograms#COLUMN_INTERNAL_PROVIDER_ID
+     * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_INTERNAL_PROVIDER_ID
      */
     public String getInternalProviderId() {
         return mValues.getAsString(PreviewPrograms.COLUMN_INTERNAL_PROVIDER_ID);
@@ -151,7 +151,7 @@
 
     /**
      * @return The preview video URI for the program.
-     * @see PreviewPrograms#COLUMN_PREVIEW_VIDEO_URI
+     * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_PREVIEW_VIDEO_URI
      */
     public Uri getPreviewVideoUri() {
         String uri = mValues.getAsString(PreviewPrograms.COLUMN_PREVIEW_VIDEO_URI);
@@ -160,7 +160,8 @@
 
     /**
      * @return The last playback position of the program in millis.
-     * @see PreviewPrograms#COLUMN_LAST_PLAYBACK_POSITION_MILLIS
+     * @see android.support.media.tv.TvContractCompat
+     * .PreviewPrograms#COLUMN_LAST_PLAYBACK_POSITION_MILLIS
      */
     public int getLastPlaybackPositionMillis() {
         Integer i = mValues.getAsInteger(PreviewPrograms.COLUMN_LAST_PLAYBACK_POSITION_MILLIS);
@@ -169,7 +170,7 @@
 
     /**
      * @return The duration of the program in millis.
-     * @see PreviewPrograms#COLUMN_DURATION_MILLIS
+     * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_DURATION_MILLIS
      */
     public int getDurationMillis() {
         Integer i = mValues.getAsInteger(PreviewPrograms.COLUMN_DURATION_MILLIS);
@@ -178,7 +179,7 @@
 
     /**
      * @return The intent URI which is launched when the program is selected.
-     * @see PreviewPrograms#COLUMN_INTENT_URI
+     * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_INTENT_URI
      */
     public Uri getIntentUri() {
         String uri = mValues.getAsString(PreviewPrograms.COLUMN_INTENT_URI);
@@ -187,7 +188,7 @@
 
     /**
      * @return The intent which is launched when the program is selected.
-     * @see PreviewPrograms#COLUMN_INTENT_URI
+     * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_INTENT_URI
      */
     public Intent getIntent() throws URISyntaxException {
         String uri = mValues.getAsString(PreviewPrograms.COLUMN_INTENT_URI);
@@ -196,7 +197,7 @@
 
     /**
      * @return Whether the program is transient or not.
-     * @see PreviewPrograms#COLUMN_TRANSIENT
+     * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_TRANSIENT
      */
     public boolean isTransient() {
         Integer i = mValues.getAsInteger(PreviewPrograms.COLUMN_TRANSIENT);
@@ -205,7 +206,7 @@
 
     /**
      * @return The type of the program.
-     * @see PreviewPrograms#COLUMN_TYPE
+     * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_TYPE
      */
     public @Type int getType() {
         Integer i = mValues.getAsInteger(PreviewPrograms.COLUMN_TYPE);
@@ -214,8 +215,8 @@
 
     /**
      * @return The poster art aspect ratio for the program.
-     * @see PreviewPrograms#COLUMN_POSTER_ART_ASPECT_RATIO
-     * @see PreviewPrograms#COLUMN_POSTER_ART_URI
+     * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_POSTER_ART_ASPECT_RATIO
+     * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_POSTER_ART_URI
      */
     public @AspectRatio int getPosterArtAspectRatio() {
         Integer i = mValues.getAsInteger(PreviewPrograms.COLUMN_POSTER_ART_ASPECT_RATIO);
@@ -224,8 +225,8 @@
 
     /**
      * @return The thumbnail aspect ratio for the program.
-     * @see PreviewPrograms#COLUMN_THUMBNAIL_ASPECT_RATIO
-     * @see PreviewPrograms#COLUMN_THUMBNAIL_URI
+     * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_THUMBNAIL_ASPECT_RATIO
+     * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_THUMBNAIL_URI
      */
     public @AspectRatio int getThumbnailAspectRatio() {
         Integer i = mValues.getAsInteger(PreviewPrograms.COLUMN_THUMBNAIL_ASPECT_RATIO);
@@ -234,7 +235,7 @@
 
     /**
      * @return The logo URI for the program.
-     * @see PreviewPrograms#COLUMN_LOGO_URI
+     * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_LOGO_URI
      */
     public Uri getLogoUri() {
         String uri = mValues.getAsString(PreviewPrograms.COLUMN_LOGO_URI);
@@ -243,7 +244,7 @@
 
     /**
      * @return The availability of the program.
-     * @see PreviewPrograms#COLUMN_AVAILABILITY
+     * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_AVAILABILITY
      */
     public @Availability int getAvailability() {
         Integer i = mValues.getAsInteger(PreviewPrograms.COLUMN_AVAILABILITY);
@@ -252,7 +253,7 @@
 
     /**
      * @return The starting price of the program.
-     * @see PreviewPrograms#COLUMN_STARTING_PRICE
+     * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_STARTING_PRICE
      */
     public String getStartingPrice() {
         return mValues.getAsString(PreviewPrograms.COLUMN_STARTING_PRICE);
@@ -260,7 +261,7 @@
 
     /**
      * @return The offer price of the program.
-     * @see PreviewPrograms#COLUMN_OFFER_PRICE
+     * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_OFFER_PRICE
      */
     public String getOfferPrice() {
         return mValues.getAsString(PreviewPrograms.COLUMN_OFFER_PRICE);
@@ -268,7 +269,7 @@
 
     /**
      * @return The release date of the program.
-     * @see PreviewPrograms#COLUMN_RELEASE_DATE
+     * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_RELEASE_DATE
      */
     public String getReleaseDate() {
         return mValues.getAsString(PreviewPrograms.COLUMN_RELEASE_DATE);
@@ -276,7 +277,7 @@
 
     /**
      * @return The item count for the program.
-     * @see PreviewPrograms#COLUMN_ITEM_COUNT
+     * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_ITEM_COUNT
      */
     public int getItemCount() {
         Integer i = mValues.getAsInteger(PreviewPrograms.COLUMN_ITEM_COUNT);
@@ -285,7 +286,7 @@
 
     /**
      * @return Whether the program is live or not.
-     * @see PreviewPrograms#COLUMN_LIVE
+     * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_LIVE
      */
     public boolean isLive() {
         Integer i = mValues.getAsInteger(PreviewPrograms.COLUMN_LIVE);
@@ -294,7 +295,7 @@
 
     /**
      * @return The interaction type for the program.
-     * @see PreviewPrograms#COLUMN_INTERACTION_TYPE
+     * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_INTERACTION_TYPE
      */
     public @InteractionType int getInteractionType() {
         Integer i = mValues.getAsInteger(PreviewPrograms.COLUMN_INTERACTION_TYPE);
@@ -303,7 +304,7 @@
 
     /**
      * @return The interaction count for the program.
-     * @see PreviewPrograms#COLUMN_INTERACTION_COUNT
+     * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_INTERACTION_COUNT
      */
     public long getInteractionCount() {
         Long l = mValues.getAsLong(PreviewPrograms.COLUMN_INTERACTION_COUNT);
@@ -312,7 +313,7 @@
 
     /**
      * @return The author for the program.
-     * @see PreviewPrograms#COLUMN_AUTHOR
+     * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_AUTHOR
      */
     public String getAuthor() {
         return mValues.getAsString(PreviewPrograms.COLUMN_AUTHOR);
@@ -320,7 +321,7 @@
 
     /**
      * @return Whether the program is browsable or not.
-     * @see PreviewPrograms#COLUMN_BROWSABLE;
+     * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_BROWSABLE
      */
     public boolean isBrowsable() {
         Integer i = mValues.getAsInteger(PreviewPrograms.COLUMN_BROWSABLE);
@@ -329,7 +330,7 @@
 
     /**
      * @return The content ID for the program.
-     * @see PreviewPrograms#COLUMN_CONTENT_ID
+     * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_CONTENT_ID
      */
     public String getContentId() {
         return mValues.getAsString(PreviewPrograms.COLUMN_CONTENT_ID);
@@ -337,8 +338,9 @@
 
     /**
      * @return The logo content description for the program.
-     * @see PreviewPrograms#COLUMN_LOGO_CONTENT_DESCRIPTION
-     * @see PreviewPrograms#COLUMN_LOGO_URI
+     * @see android.support.media.tv.TvContractCompat
+     * .PreviewPrograms#COLUMN_LOGO_CONTENT_DESCRIPTION
+     * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_LOGO_URI
      */
     public String getLogoContentDescription() {
         return mValues.getAsString(PreviewPrograms.COLUMN_LOGO_CONTENT_DESCRIPTION);
@@ -346,7 +348,7 @@
 
     /**
      * @return The genre for the program.
-     * @see PreviewPrograms#COLUMN_GENRE
+     * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_GENRE
      */
     public String getGenre() {
         return mValues.getAsString(PreviewPrograms.COLUMN_GENRE);
@@ -354,7 +356,7 @@
 
     /**
      * @return The start time for the program.
-     * @see PreviewPrograms#COLUMN_START_TIME_UTC_MILLIS
+     * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_START_TIME_UTC_MILLIS
      */
     public long getStartTimeUtcMillis() {
         Long l = mValues.getAsLong(PreviewPrograms.COLUMN_START_TIME_UTC_MILLIS);
@@ -363,7 +365,7 @@
 
     /**
      * @return The end time for the program.
-     * @see PreviewPrograms#COLUMN_END_TIME_UTC_MILLIS
+     * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_END_TIME_UTC_MILLIS
      */
     public long getEndTimeUtcMillis() {
         Long l = mValues.getAsLong(PreviewPrograms.COLUMN_END_TIME_UTC_MILLIS);
@@ -372,7 +374,7 @@
 
     /**
      * @return The preview audio URI for the program.
-     * @see PreviewPrograms#COLUMN_PREVIEW_AUDIO_URI
+     * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_PREVIEW_AUDIO_URI
      */
     public Uri getPreviewAudioUri() {
         String uri = mValues.getAsString(PreviewPrograms.COLUMN_PREVIEW_AUDIO_URI);
@@ -628,7 +630,8 @@
          *
          * @param externalId The internal provider ID for the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see PreviewPrograms#COLUMN_INTERNAL_PROVIDER_ID
+         * @see android.support.media.tv.TvContractCompat
+         * .PreviewPrograms#COLUMN_INTERNAL_PROVIDER_ID
          */
         public T setInternalProviderId(String externalId) {
             mValues.put(PreviewPrograms.COLUMN_INTERNAL_PROVIDER_ID, externalId);
@@ -640,7 +643,7 @@
          *
          * @param previewVideoUri The preview video URI for the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see PreviewPrograms#COLUMN_PREVIEW_VIDEO_URI
+         * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_PREVIEW_VIDEO_URI
          */
         public T setPreviewVideoUri(Uri previewVideoUri) {
             mValues.put(PreviewPrograms.COLUMN_PREVIEW_VIDEO_URI,
@@ -653,7 +656,8 @@
          *
          * @param position The last playback posirion for the program in millis.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see PreviewPrograms#COLUMN_LAST_PLAYBACK_POSITION_MILLIS
+         * @see android.support.media.tv.TvContractCompat
+         * .PreviewPrograms#COLUMN_LAST_PLAYBACK_POSITION_MILLIS
          */
         public T setLastPlaybackPositionMillis(int position) {
             mValues.put(PreviewPrograms.COLUMN_LAST_PLAYBACK_POSITION_MILLIS, position);
@@ -665,7 +669,7 @@
          *
          * @param duration The duration the program in millis.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see PreviewPrograms#COLUMN_DURATION_MILLIS
+         * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_DURATION_MILLIS
          */
         public T setDurationMillis(int duration) {
             mValues.put(PreviewPrograms.COLUMN_DURATION_MILLIS, duration);
@@ -677,7 +681,7 @@
          *
          * @param intentUri The intent URI for the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see PreviewPrograms#COLUMN_INTENT_URI
+         * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_INTENT_URI
          */
         public T setIntentUri(Uri intentUri) {
             mValues.put(PreviewPrograms.COLUMN_INTENT_URI,
@@ -700,7 +704,7 @@
          *
          * @param transientValue Whether the program is transient or not.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see PreviewPrograms#COLUMN_TRANSIENT
+         * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_TRANSIENT
          */
         public T setTransient(boolean transientValue) {
             mValues.put(PreviewPrograms.COLUMN_TRANSIENT, transientValue ? IS_TRANSIENT : 0);
@@ -711,23 +715,23 @@
          * Sets the type of this program content.
          *
          * <p>The value should match one of the followings:
-         * {@link PreviewPrograms#TYPE_MOVIE},
-         * {@link PreviewPrograms#TYPE_TV_SERIES},
-         * {@link PreviewPrograms#TYPE_TV_SEASON},
-         * {@link PreviewPrograms#TYPE_TV_EPISODE},
-         * {@link PreviewPrograms#TYPE_CLIP},
-         * {@link PreviewPrograms#TYPE_EVENT},
-         * {@link PreviewPrograms#TYPE_CHANNEL},
-         * {@link PreviewPrograms#TYPE_TRACK},
-         * {@link PreviewPrograms#TYPE_ALBUM},
-         * {@link PreviewPrograms#TYPE_ARTIST},
-         * {@link PreviewPrograms#TYPE_PLAYLIST},
-         * {@link PreviewPrograms#TYPE_STATION}, and
-         * {@link PreviewPrograms#TYPE_GAME}.
+         * {@link android.support.media.tv.TvContractCompat.PreviewPrograms#TYPE_MOVIE},
+         * {@link android.support.media.tv.TvContractCompat.PreviewPrograms#TYPE_TV_SERIES},
+         * {@link android.support.media.tv.TvContractCompat.PreviewPrograms#TYPE_TV_SEASON},
+         * {@link android.support.media.tv.TvContractCompat.PreviewPrograms#TYPE_TV_EPISODE},
+         * {@link android.support.media.tv.TvContractCompat.PreviewPrograms#TYPE_CLIP},
+         * {@link android.support.media.tv.TvContractCompat.PreviewPrograms#TYPE_EVENT},
+         * {@link android.support.media.tv.TvContractCompat.PreviewPrograms#TYPE_CHANNEL},
+         * {@link android.support.media.tv.TvContractCompat.PreviewPrograms#TYPE_TRACK},
+         * {@link android.support.media.tv.TvContractCompat.PreviewPrograms#TYPE_ALBUM},
+         * {@link android.support.media.tv.TvContractCompat.PreviewPrograms#TYPE_ARTIST},
+         * {@link android.support.media.tv.TvContractCompat.PreviewPrograms#TYPE_PLAYLIST},
+         * {@link android.support.media.tv.TvContractCompat.PreviewPrograms#TYPE_STATION}, and
+         * {@link android.support.media.tv.TvContractCompat.PreviewPrograms#TYPE_GAME}.
          *
          * @param type The type of the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see PreviewPrograms#COLUMN_TYPE
+         * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_TYPE
          */
         public T setType(@Type int type) {
             mValues.put(PreviewPrograms.COLUMN_TYPE, type);
@@ -738,17 +742,19 @@
          * Sets the aspect ratio of the poster art for this TV program.
          *
          * <p>The value should match one of the followings:
-         * {@link PreviewPrograms#ASPECT_RATIO_16_9},
-         * {@link PreviewPrograms#ASPECT_RATIO_3_2},
-         * {@link PreviewPrograms#ASPECT_RATIO_4_3},
-         * {@link PreviewPrograms#ASPECT_RATIO_1_1},
-         * {@link PreviewPrograms#ASPECT_RATIO_2_3}, and
-         * {@link PreviewPrograms#ASPECT_RATIO_MOVIE_POSTER}.
+         * {@link android.support.media.tv.TvContractCompat.PreviewPrograms#ASPECT_RATIO_16_9},
+         * {@link android.support.media.tv.TvContractCompat.PreviewPrograms#ASPECT_RATIO_3_2},
+         * {@link android.support.media.tv.TvContractCompat.PreviewPrograms#ASPECT_RATIO_4_3},
+         * {@link android.support.media.tv.TvContractCompat.PreviewPrograms#ASPECT_RATIO_1_1},
+         * {@link android.support.media.tv.TvContractCompat.PreviewPrograms#ASPECT_RATIO_2_3}, and
+         * {@link android.support.media.tv.TvContractCompat
+         * .PreviewPrograms#ASPECT_RATIO_MOVIE_POSTER}.
          *
          * @param ratio The poster art aspect ratio for the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see PreviewPrograms#COLUMN_POSTER_ART_ASPECT_RATIO
-         * @see PreviewPrograms#COLUMN_POSTER_ART_URI
+         * @see android.support.media.tv.TvContractCompat
+         * .PreviewPrograms#COLUMN_POSTER_ART_ASPECT_RATIO
+         * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_POSTER_ART_URI
          */
         public T setPosterArtAspectRatio(@AspectRatio int ratio) {
             mValues.put(PreviewPrograms.COLUMN_POSTER_ART_ASPECT_RATIO, ratio);
@@ -759,16 +765,18 @@
          * Sets the aspect ratio of the thumbnail for this TV program.
          *
          * <p>The value should match one of the followings:
-         * {@link PreviewPrograms#ASPECT_RATIO_16_9},
-         * {@link PreviewPrograms#ASPECT_RATIO_3_2},
-         * {@link PreviewPrograms#ASPECT_RATIO_4_3},
-         * {@link PreviewPrograms#ASPECT_RATIO_1_1},
-         * {@link PreviewPrograms#ASPECT_RATIO_2_3}, and
-         * {@link PreviewPrograms#ASPECT_RATIO_MOVIE_POSTER}.
+         * {@link android.support.media.tv.TvContractCompat.PreviewPrograms#ASPECT_RATIO_16_9},
+         * {@link android.support.media.tv.TvContractCompat.PreviewPrograms#ASPECT_RATIO_3_2},
+         * {@link android.support.media.tv.TvContractCompat.PreviewPrograms#ASPECT_RATIO_4_3},
+         * {@link android.support.media.tv.TvContractCompat.PreviewPrograms#ASPECT_RATIO_1_1},
+         * {@link android.support.media.tv.TvContractCompat.PreviewPrograms#ASPECT_RATIO_2_3}, and
+         * {@link android.support.media.tv.TvContractCompat
+         * .PreviewPrograms#ASPECT_RATIO_MOVIE_POSTER}.
          *
          * @param ratio The thumbnail aspect ratio of the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see PreviewPrograms#COLUMN_THUMBNAIL_ASPECT_RATIO
+         * @see android.support.media.tv.TvContractCompat
+         * .PreviewPrograms#COLUMN_THUMBNAIL_ASPECT_RATIO
          */
         public T setThumbnailAspectRatio(@AspectRatio int ratio) {
             mValues.put(PreviewPrograms.COLUMN_THUMBNAIL_ASPECT_RATIO, ratio);
@@ -780,7 +788,7 @@
          *
          * @param logoUri The logo URI for the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see PreviewPrograms#COLUMN_LOGO_URI
+         * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_LOGO_URI
          */
         public T setLogoUri(Uri logoUri) {
             mValues.put(PreviewPrograms.COLUMN_LOGO_URI,
@@ -792,15 +800,20 @@
          * Sets the availability of this TV program.
          *
          * <p>The value should match one of the followings:
-         * {@link PreviewPrograms#AVAILABILITY_AVAILABLE},
-         * {@link PreviewPrograms#AVAILABILITY_FREE_WITH_SUBSCRIPTION},
-         * {@link PreviewPrograms#AVAILABILITY_PAID_CONTENT},
-         * {@link PreviewPrograms#AVAILABILITY_PURCHASED}, and
-         * {@link PreviewPrograms#AVAILABILITY_FREE}.
+         * {@link android.support.media.tv.TvContractCompat
+         * .PreviewPrograms#AVAILABILITY_AVAILABLE},
+         * {@link android.support.media.tv.TvContractCompat
+         * .PreviewPrograms#AVAILABILITY_FREE_WITH_SUBSCRIPTION},
+         * {@link android.support.media.tv.TvContractCompat
+         * .PreviewPrograms#AVAILABILITY_PAID_CONTENT},
+         * {@link android.support.media.tv.TvContractCompat
+         * .PreviewPrograms#AVAILABILITY_PURCHASED}, and
+         * {@link android.support.media.tv.TvContractCompat
+         * .PreviewPrograms#AVAILABILITY_FREE}.
          *
          * @param availability The availability of the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see PreviewPrograms#COLUMN_AVAILABILITY
+         * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_AVAILABILITY
          */
         public T setAvailability(@Availability int availability) {
             mValues.put(PreviewPrograms.COLUMN_AVAILABILITY, availability);
@@ -812,7 +825,7 @@
          *
          * @param price The starting price of the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see PreviewPrograms#COLUMN_STARTING_PRICE
+         * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_STARTING_PRICE
          */
         public T setStartingPrice(String price) {
             mValues.put(PreviewPrograms.COLUMN_STARTING_PRICE, price);
@@ -824,7 +837,7 @@
          *
          * @param price The offer price of the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see PreviewPrograms#COLUMN_OFFER_PRICE
+         * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_OFFER_PRICE
          */
         public T setOfferPrice(String price) {
             mValues.put(PreviewPrograms.COLUMN_OFFER_PRICE, price);
@@ -839,7 +852,7 @@
          *
          * @param releaseDate The release date of the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see PreviewPrograms#COLUMN_RELEASE_DATE
+         * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_RELEASE_DATE
          */
         public T setReleaseDate(String releaseDate) {
             mValues.put(PreviewPrograms.COLUMN_RELEASE_DATE, releaseDate);
@@ -851,7 +864,7 @@
          *
          * @param releaseDate The release date of the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see PreviewPrograms#COLUMN_RELEASE_DATE
+         * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_RELEASE_DATE
          */
         public T setReleaseDate(Date releaseDate) {
             mValues.put(PreviewPrograms.COLUMN_RELEASE_DATE, sFormat.format(releaseDate));
@@ -863,7 +876,7 @@
          *
          * @param itemCount The item count for the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see PreviewPrograms#COLUMN_ITEM_COUNT
+         * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_ITEM_COUNT
          */
         public T setItemCount(int itemCount) {
             mValues.put(PreviewPrograms.COLUMN_ITEM_COUNT, itemCount);
@@ -875,7 +888,7 @@
          *
          * @param live Whether the program is live or not.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see PreviewPrograms#COLUMN_LIVE
+         * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_LIVE
          */
         public T setLive(boolean live) {
             mValues.put(PreviewPrograms.COLUMN_LIVE, live ? IS_LIVE : 0);
@@ -886,17 +899,22 @@
          * Sets the type of interaction for this TV program.
          *
          * <p> The value should match one of the followings:
-         * {@link PreviewPrograms#INTERACTION_TYPE_LISTENS},
-         * {@link PreviewPrograms#INTERACTION_TYPE_FOLLOWERS},
-         * {@link PreviewPrograms#INTERACTION_TYPE_FANS},
-         * {@link PreviewPrograms#INTERACTION_TYPE_LIKES},
-         * {@link PreviewPrograms#INTERACTION_TYPE_THUMBS},
-         * {@link PreviewPrograms#INTERACTION_TYPE_VIEWS}, and
-         * {@link PreviewPrograms#INTERACTION_TYPE_VIEWERS}.
+         * {@link android.support.media.tv.TvContractCompat
+         * .PreviewPrograms#INTERACTION_TYPE_LISTENS},
+         * {@link android.support.media.tv.TvContractCompat
+         * .PreviewPrograms#INTERACTION_TYPE_FOLLOWERS},
+         * {@link android.support.media.tv.TvContractCompat.PreviewPrograms#INTERACTION_TYPE_FANS},
+         * {@link android.support.media.tv.TvContractCompat.PreviewPrograms#INTERACTION_TYPE_LIKES},
+         * {@link android.support.media.tv.TvContractCompat
+         * .PreviewPrograms#INTERACTION_TYPE_THUMBS},
+         * {@link android.support.media.tv.TvContractCompat.PreviewPrograms#INTERACTION_TYPE_VIEWS},
+         * and
+         * {@link android.support.media.tv.TvContractCompat
+         * .PreviewPrograms#INTERACTION_TYPE_VIEWERS}.
          *
          * @param interactionType The interaction type of the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see PreviewPrograms#COLUMN_INTERACTION_TYPE
+         * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_INTERACTION_TYPE
          */
         public T setInteractionType(@InteractionType int interactionType) {
             mValues.put(PreviewPrograms.COLUMN_INTERACTION_TYPE, interactionType);
@@ -908,7 +926,7 @@
          *
          * @param interactionCount The interaction count for the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see PreviewPrograms#COLUMN_INTERACTION_COUNT
+         * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_INTERACTION_COUNT
          */
         public T setInteractionCount(long interactionCount) {
             mValues.put(PreviewPrograms.COLUMN_INTERACTION_COUNT, interactionCount);
@@ -920,7 +938,7 @@
          *
          * @param author The author of the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see PreviewPrograms#COLUMN_AUTHOR
+         * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_AUTHOR
          */
         public T setAuthor(String author) {
             mValues.put(PreviewPrograms.COLUMN_AUTHOR, author);
@@ -932,7 +950,7 @@
          *
          * @param browsable Whether the program is browsable or not.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see PreviewPrograms#COLUMN_BROWSABLE
+         * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_BROWSABLE
          * @hide
          */
         @RestrictTo(LIBRARY_GROUP)
@@ -946,7 +964,7 @@
          *
          * @param contentId The content ID for the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see PreviewPrograms#COLUMN_CONTENT_ID
+         * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_CONTENT_ID
          */
         public T setContentId(String contentId) {
             mValues.put(PreviewPrograms.COLUMN_CONTENT_ID, contentId);
@@ -959,8 +977,9 @@
          * @param logoContentDescription The content description for the logo displayed in the
          *                               program.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see PreviewPrograms#COLUMN_LOGO_CONTENT_DESCRIPTION
-         * @see PreviewPrograms#COLUMN_LOGO_URI
+         * @see android.support.media.tv.TvContractCompat
+         * .PreviewPrograms#COLUMN_LOGO_CONTENT_DESCRIPTION
+         * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_LOGO_URI
          */
         public T setLogoContentDescription(String logoContentDescription) {
             mValues.put(PreviewPrograms.COLUMN_LOGO_CONTENT_DESCRIPTION, logoContentDescription);
@@ -972,7 +991,7 @@
          *
          * @param genre The genre for the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see PreviewPrograms#COLUMN_GENRE
+         * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_GENRE
          */
         public T setGenre(String genre) {
             mValues.put(PreviewPrograms.COLUMN_GENRE, genre);
@@ -984,7 +1003,8 @@
          *
          * @param startTime The start time for the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see PreviewPrograms#COLUMN_START_TIME_UTC_MILLIS
+         * @see android.support.media.tv.TvContractCompat
+         * .PreviewPrograms#COLUMN_START_TIME_UTC_MILLIS
          */
         public T setStartTimeUtcMillis(long startTime) {
             mValues.put(PreviewPrograms.COLUMN_START_TIME_UTC_MILLIS, startTime);
@@ -996,7 +1016,7 @@
          *
          * @param endTime The end time for the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see PreviewPrograms#COLUMN_END_TIME_UTC_MILLIS
+         * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_END_TIME_UTC_MILLIS
          */
         public T setEndTimeUtcMillis(long endTime) {
             mValues.put(PreviewPrograms.COLUMN_END_TIME_UTC_MILLIS, endTime);
@@ -1008,7 +1028,7 @@
          *
          * @param previewAudioUri The preview audio URI for the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see PreviewPrograms#COLUMN_PREVIEW_AUDIO_URI
+         * @see android.support.media.tv.TvContractCompat.PreviewPrograms#COLUMN_PREVIEW_AUDIO_URI
          */
         public T setPreviewAudioUri(Uri previewAudioUri) {
             mValues.put(PreviewPrograms.COLUMN_PREVIEW_AUDIO_URI,
diff --git a/tv-provider/src/main/java/android/support/media/tv/BaseProgram.java b/tv-provider/src/main/java/android/support/media/tv/BaseProgram.java
index 4c7882d..13425ac 100644
--- a/tv-provider/src/main/java/android/support/media/tv/BaseProgram.java
+++ b/tv-provider/src/main/java/android/support/media/tv/BaseProgram.java
@@ -77,7 +77,7 @@
 
     /**
      * @return The ID for the program.
-     * @see BaseTvColumns#_ID
+     * @see android.support.media.tv.TvContractCompat.BaseTvColumns#_ID
      */
     public long getId() {
         Long l = mValues.getAsLong(BaseTvColumns._ID);
@@ -86,7 +86,7 @@
 
     /**
      * @return The package name for the program.
-     * @see BaseTvColumns#COLUMN_PACKAGE_NAME
+     * @see android.support.media.tv.TvContractCompat.BaseTvColumns#COLUMN_PACKAGE_NAME
      * @hide
      */
     @RestrictTo(LIBRARY_GROUP)
@@ -96,7 +96,7 @@
 
     /**
      * @return The title for the program.
-     * @see Programs#COLUMN_TITLE
+     * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_TITLE
      */
     public String getTitle() {
         return mValues.getAsString(Programs.COLUMN_TITLE);
@@ -104,7 +104,7 @@
 
     /**
      * @return The episode title for the program.
-     * @see Programs#COLUMN_EPISODE_TITLE
+     * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_EPISODE_TITLE
      */
     public String getEpisodeTitle() {
         return mValues.getAsString(Programs.COLUMN_EPISODE_TITLE);
@@ -112,7 +112,7 @@
 
     /**
      * @return The season display number for the program.
-     * @see Programs#COLUMN_SEASON_DISPLAY_NUMBER
+     * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_SEASON_DISPLAY_NUMBER
      */
     public String getSeasonNumber() {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
@@ -124,7 +124,7 @@
 
     /**
      * @return The episode display number for the program.
-     * @see Programs#COLUMN_EPISODE_DISPLAY_NUMBER
+     * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_EPISODE_DISPLAY_NUMBER
      */
     public String getEpisodeNumber() {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
@@ -136,7 +136,7 @@
 
     /**
      * @return The short description for the program.
-     * @see Programs#COLUMN_SHORT_DESCRIPTION
+     * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_SHORT_DESCRIPTION
      */
     public String getDescription() {
         return mValues.getAsString(Programs.COLUMN_SHORT_DESCRIPTION);
@@ -144,7 +144,7 @@
 
     /**
      * @return The long description for the program.
-     * @see Programs#COLUMN_LONG_DESCRIPTION
+     * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_LONG_DESCRIPTION
      */
     public String getLongDescription() {
         return mValues.getAsString(Programs.COLUMN_LONG_DESCRIPTION);
@@ -152,7 +152,7 @@
 
     /**
      * @return The video width for the program.
-     * @see Programs#COLUMN_VIDEO_WIDTH
+     * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_VIDEO_WIDTH
      */
     public int getVideoWidth() {
         Integer i = mValues.getAsInteger(Programs.COLUMN_VIDEO_WIDTH);
@@ -161,7 +161,7 @@
 
     /**
      * @return The video height for the program.
-     * @see Programs#COLUMN_VIDEO_HEIGHT
+     * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_VIDEO_HEIGHT
      */
     public int getVideoHeight() {
         Integer i = mValues.getAsInteger(Programs.COLUMN_VIDEO_HEIGHT);
@@ -170,7 +170,7 @@
 
     /**
      * @return The canonical genre for the program.
-     * @see Programs#COLUMN_CANONICAL_GENRE
+     * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_CANONICAL_GENRE
      */
     public @Genre String[] getCanonicalGenres() {
         return Programs.Genres.decode(mValues.getAsString(Programs.COLUMN_CANONICAL_GENRE));
@@ -178,7 +178,7 @@
 
     /**
      * @return The content rating for the program.
-     * @see Programs#COLUMN_CONTENT_RATING
+     * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_CONTENT_RATING
      */
     public TvContentRating[] getContentRatings() {
         return TvContractUtils.stringToContentRatings(mValues.getAsString(
@@ -187,7 +187,7 @@
 
     /**
      * @return The poster art URI for the program.
-     * @see Programs#COLUMN_POSTER_ART_URI
+     * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_POSTER_ART_URI
      */
     public Uri getPosterArtUri() {
         String uri = mValues.getAsString(Programs.COLUMN_POSTER_ART_URI);
@@ -196,7 +196,7 @@
 
     /**
      * @return The thumbnail URI for the program.
-     * @see Programs#COLUMN_THUMBNAIL_URI
+     * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_THUMBNAIL_URI
      */
     public Uri getThumbnailUri() {
         String uri = mValues.getAsString(Programs.COLUMN_POSTER_ART_URI);
@@ -205,7 +205,7 @@
 
     /**
      * @return The internal provider data for the program.
-     * @see Programs#COLUMN_INTERNAL_PROVIDER_DATA
+     * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_INTERNAL_PROVIDER_DATA
      */
     public byte[] getInternalProviderDataByteArray() {
         return mValues.getAsByteArray(Programs.COLUMN_INTERNAL_PROVIDER_DATA);
@@ -213,7 +213,7 @@
 
     /**
      * @return The audio languages for the program.
-     * @see Programs#COLUMN_AUDIO_LANGUAGE
+     * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_AUDIO_LANGUAGE
      */
     public String[] getAudioLanguages() {
         return TvContractUtils.stringToAudioLanguages(mValues.getAsString(
@@ -222,7 +222,7 @@
 
     /**
      * @return Whether the program is searchable or not.
-     * @see Programs#COLUMN_SEARCHABLE
+     * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_SEARCHABLE
      */
     public boolean isSearchable() {
         Integer i = mValues.getAsInteger(Programs.COLUMN_SEARCHABLE);
@@ -231,7 +231,7 @@
 
     /**
      * @return The first internal provider flag for the program.
-     * @see Programs#COLUMN_INTERNAL_PROVIDER_FLAG1
+     * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_INTERNAL_PROVIDER_FLAG1
      */
     public Long getInternalProviderFlag1() {
         return mValues.getAsLong(Programs.COLUMN_INTERNAL_PROVIDER_FLAG1);
@@ -239,7 +239,7 @@
 
     /**
      * @return The second internal provider flag for the program.
-     * @see Programs#COLUMN_INTERNAL_PROVIDER_FLAG2
+     * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_INTERNAL_PROVIDER_FLAG2
      */
     public Long getInternalProviderFlag2() {
         return mValues.getAsLong(Programs.COLUMN_INTERNAL_PROVIDER_FLAG2);
@@ -247,7 +247,7 @@
 
     /**
      * @return The third internal provider flag for the program.
-     * @see Programs#COLUMN_INTERNAL_PROVIDER_FLAG3
+     * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_INTERNAL_PROVIDER_FLAG3
      */
     public Long getInternalProviderFlag3() {
         return mValues.getAsLong(Programs.COLUMN_INTERNAL_PROVIDER_FLAG3);
@@ -255,7 +255,7 @@
 
     /**
      * @return The forth internal provider flag for the program.
-     * @see Programs#COLUMN_INTERNAL_PROVIDER_FLAG4
+     * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_INTERNAL_PROVIDER_FLAG4
      */
     public Long getInternalProviderFlag4() {
         return mValues.getAsLong(Programs.COLUMN_INTERNAL_PROVIDER_FLAG4);
@@ -263,7 +263,7 @@
 
     /**
      * @return The season title for the program.
-     * @see Programs#COLUMN_SEASON_TITLE
+     * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_SEASON_TITLE
      */
     public String getSeasonTitle() {
         return mValues.getAsString(Programs.COLUMN_SEASON_TITLE);
@@ -271,7 +271,7 @@
 
     /**
      * @return The review rating style for the program.
-     * @see Programs#COLUMN_REVIEW_RATING_STYLE
+     * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_REVIEW_RATING_STYLE
      */
     public @ReviewRatingStyle int getReviewRatingStyle() {
         Integer i = mValues.getAsInteger(Programs.COLUMN_REVIEW_RATING_STYLE);
@@ -280,7 +280,7 @@
 
     /**
      * @return The review rating for the program.
-     * @see Programs#COLUMN_REVIEW_RATING
+     * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_REVIEW_RATING
      */
     public String getReviewRating() {
         return mValues.getAsString(Programs.COLUMN_REVIEW_RATING);
@@ -542,7 +542,7 @@
          *
          * @param programId The ID for the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see BaseTvColumns#_ID
+         * @see android.support.media.tv.TvContractCompat.BaseTvColumns#_ID
          */
         public T setId(long programId) {
             mValues.put(BaseTvColumns._ID, programId);
@@ -554,7 +554,7 @@
          *
          * @param packageName The package name for the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see BaseTvColumns#COLUMN_PACKAGE_NAME
+         * @see android.support.media.tv.TvContractCompat.BaseTvColumns#COLUMN_PACKAGE_NAME
          * @hide
          */
         @RestrictTo(LIBRARY_GROUP)
@@ -568,7 +568,7 @@
          *
          * @param title The title for the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see Programs#COLUMN_TITLE
+         * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_TITLE
          */
         public T setTitle(String title) {
             mValues.put(Programs.COLUMN_TITLE, title);
@@ -580,7 +580,7 @@
          *
          * @param episodeTitle The episode title for the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see Programs#COLUMN_EPISODE_TITLE
+         * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_EPISODE_TITLE
          */
         public T setEpisodeTitle(String episodeTitle) {
             mValues.put(Programs.COLUMN_EPISODE_TITLE, episodeTitle);
@@ -592,7 +592,7 @@
          *
          * @param seasonNumber The season display number for the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see Programs#COLUMN_SEASON_DISPLAY_NUMBER
+         * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_SEASON_DISPLAY_NUMBER
          */
         public T setSeasonNumber(int seasonNumber) {
             setSeasonNumber(String.valueOf(seasonNumber), seasonNumber);
@@ -603,11 +603,12 @@
          * Sets the season number for this episode for a series.
          *
          * @param seasonNumber The season display number for the program.
-         * @param numericalSeasonNumber An integer value for {@link Programs#COLUMN_SEASON_NUMBER}
-         *                              which will be used for API Level 23 and below.
+         * @param numericalSeasonNumber An integer value for
+         * {@link android.support.media.tv.TvContractCompat.Programs#COLUMN_SEASON_NUMBER}
+         * which will be used for API Level 23 and below.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see Programs#COLUMN_SEASON_DISPLAY_NUMBER
-         * @see Programs#COLUMN_SEASON_NUMBER
+         * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_SEASON_DISPLAY_NUMBER
+         * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_SEASON_NUMBER
          */
         public T setSeasonNumber(String seasonNumber, int numericalSeasonNumber) {
             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
@@ -623,7 +624,7 @@
          *
          * @param episodeNumber The value of episode display number for the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see Programs#COLUMN_EPISODE_DISPLAY_NUMBER
+         * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_EPISODE_DISPLAY_NUMBER
          */
         public T setEpisodeNumber(int episodeNumber) {
             setEpisodeNumber(String.valueOf(episodeNumber), episodeNumber);
@@ -634,11 +635,12 @@
          * Sets the episode number in a season for this episode for a series.
          *
          * @param episodeNumber The value of episode display number for the program.
-         * @param numericalEpisodeNumber An integer value for {@link Programs#COLUMN_EPISODE_NUMBER}
-         *                               which will be used for API Level 23 and below.
+         * @param numericalEpisodeNumber An integer value for
+         * {@link android.support.media.tv.TvContractCompat.Programs#COLUMN_EPISODE_NUMBER}
+         * which will be used for API Level 23 and below.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see Programs#COLUMN_EPISODE_DISPLAY_NUMBER
-         * @see Programs#COLUMN_EPISODE_NUMBER
+         * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_EPISODE_DISPLAY_NUMBER
+         * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_EPISODE_NUMBER
          */
         public T setEpisodeNumber(String episodeNumber, int numericalEpisodeNumber) {
             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
@@ -655,7 +657,7 @@
          *
          * @param description The short description for the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see Programs#COLUMN_SHORT_DESCRIPTION
+         * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_SHORT_DESCRIPTION
          */
         public T setDescription(String description) {
             mValues.put(Programs.COLUMN_SHORT_DESCRIPTION, description);
@@ -667,7 +669,7 @@
          *
          * @param longDescription The long description for the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see Programs#COLUMN_LONG_DESCRIPTION
+         * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_LONG_DESCRIPTION
          */
         public T setLongDescription(String longDescription) {
             mValues.put(Programs.COLUMN_LONG_DESCRIPTION, longDescription);
@@ -679,7 +681,7 @@
          *
          * @param width The video width for the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see Programs#COLUMN_VIDEO_WIDTH
+         * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_VIDEO_WIDTH
          */
         public T setVideoWidth(int width) {
             mValues.put(Programs.COLUMN_VIDEO_WIDTH, width);
@@ -691,7 +693,7 @@
          *
          * @param height The video height for the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see Programs#COLUMN_VIDEO_HEIGHT
+         * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_VIDEO_HEIGHT
          */
         public T setVideoHeight(int height) {
             mValues.put(Programs.COLUMN_VIDEO_HEIGHT, height);
@@ -701,10 +703,11 @@
         /**
          * Sets the content ratings for this program.
          *
-         * @param contentRatings An array of {@link TvContentRating} that apply to this program
-         *                       which will be flattened to a String to store in a database.
+         * @param contentRatings An array of {@link android.media.tv.TvContentRating} that apply to
+         *                       this program  which will be flattened to a String to store in
+         *                       a database.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see Programs#COLUMN_CONTENT_RATING
+         * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_CONTENT_RATING
          */
         public T setContentRatings(TvContentRating[] contentRatings) {
             mValues.put(Programs.COLUMN_CONTENT_RATING,
@@ -717,7 +720,7 @@
          *
          * @param posterArtUri The poster art URI for the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see Programs#COLUMN_POSTER_ART_URI
+         * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_POSTER_ART_URI
          */
         public T setPosterArtUri(Uri posterArtUri) {
             mValues.put(Programs.COLUMN_POSTER_ART_URI,
@@ -730,7 +733,7 @@
          *
          * @param thumbnailUri The thumbnail URI for the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see Programs#COLUMN_THUMBNAIL_URI
+         * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_THUMBNAIL_URI
          */
         public T setThumbnailUri(Uri thumbnailUri) {
             mValues.put(Programs.COLUMN_THUMBNAIL_URI,
@@ -741,10 +744,11 @@
         /**
          * Sets the genres of the program.
          *
-         * @param genres An array of {@link Programs.Genres} that apply to the program which will be
-         *               flattened to a String to store in a database.
+         * @param genres An array of
+         * {@link android.support.media.tv.TvContractCompat.Programs.Genres}
+         * that apply to the program which will be flattened to a String to store in a database.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see Programs#COLUMN_CANONICAL_GENRE
+         * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_CANONICAL_GENRE
          */
         public T setCanonicalGenres(@Genre String[] genres) {
             mValues.put(Programs.COLUMN_CANONICAL_GENRE, Programs.Genres.encode(genres));
@@ -756,7 +760,7 @@
          *
          * @param data The internal provider data for the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see Programs#COLUMN_INTERNAL_PROVIDER_DATA
+         * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_INTERNAL_PROVIDER_DATA
          */
         public T setInternalProviderData(byte[] data) {
             mValues.put(ProgramColumns.COLUMN_INTERNAL_PROVIDER_DATA, data);
@@ -781,7 +785,7 @@
          *
          * @param searchable Whether the program is searchable or not.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see Programs#COLUMN_SEARCHABLE
+         * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_SEARCHABLE
          */
         public T setSearchable(boolean searchable) {
             mValues.put(Programs.COLUMN_SEARCHABLE, searchable ? IS_SEARCHABLE : 0);
@@ -793,7 +797,7 @@
          *
          * @param flag The first internal provider flag for the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see Programs#COLUMN_INTERNAL_PROVIDER_FLAG1
+         * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_INTERNAL_PROVIDER_FLAG1
          */
         public T setInternalProviderFlag1(long flag) {
             mValues.put(ProgramColumns.COLUMN_INTERNAL_PROVIDER_FLAG1, flag);
@@ -805,7 +809,7 @@
          *
          * @param flag The second internal provider flag for the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see Programs#COLUMN_INTERNAL_PROVIDER_FLAG2
+         * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_INTERNAL_PROVIDER_FLAG2
          */
         public T setInternalProviderFlag2(long flag) {
             mValues.put(ProgramColumns.COLUMN_INTERNAL_PROVIDER_FLAG2, flag);
@@ -817,7 +821,7 @@
          *
          * @param flag The third internal provider flag for the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see Programs#COLUMN_INTERNAL_PROVIDER_FLAG3
+         * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_INTERNAL_PROVIDER_FLAG3
          */
         public T setInternalProviderFlag3(long flag) {
             mValues.put(ProgramColumns.COLUMN_INTERNAL_PROVIDER_FLAG3, flag);
@@ -829,7 +833,7 @@
          *
          * @param flag The forth internal provider flag for the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see Programs#COLUMN_INTERNAL_PROVIDER_FLAG4
+         * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_INTERNAL_PROVIDER_FLAG4
          */
         public T setInternalProviderFlag4(long flag) {
             mValues.put(ProgramColumns.COLUMN_INTERNAL_PROVIDER_FLAG4, flag);
@@ -842,10 +846,11 @@
          * @param reviewRatingStyle The reviewing rating style for the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
          *
-         * @see Programs#COLUMN_REVIEW_RATING_STYLE
-         * @see Programs#REVIEW_RATING_STYLE_STARS
-         * @see Programs#REVIEW_RATING_STYLE_THUMBS_UP_DOWN
-         * @see Programs#REVIEW_RATING_STYLE_PERCENTAGE
+         * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_REVIEW_RATING_STYLE
+         * @see android.support.media.tv.TvContractCompat.Programs#REVIEW_RATING_STYLE_STARS
+         * @see android.support.media.tv.TvContractCompat
+         * .Programs#REVIEW_RATING_STYLE_THUMBS_UP_DOWN
+         * @see android.support.media.tv.TvContractCompat.Programs#REVIEW_RATING_STYLE_PERCENTAGE
          */
         public T setReviewRatingStyle(@ReviewRatingStyle int reviewRatingStyle) {
             mValues.put(ProgramColumns.COLUMN_REVIEW_RATING_STYLE, reviewRatingStyle);
@@ -865,11 +870,12 @@
          * @param reviewRating The value of the review rating for the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
          *
-         * @see Programs#COLUMN_REVIEW_RATING
-         * @see Programs#COLUMN_REVIEW_RATING_STYLE
-         * @see Programs#REVIEW_RATING_STYLE_STARS
-         * @see Programs#REVIEW_RATING_STYLE_THUMBS_UP_DOWN
-         * @see Programs#REVIEW_RATING_STYLE_PERCENTAGE
+         * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_REVIEW_RATING
+         * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_REVIEW_RATING_STYLE
+         * @see android.support.media.tv.TvContractCompat.Programs#REVIEW_RATING_STYLE_STARS
+         * @see android.support.media.tv.TvContractCompat
+         * .Programs#REVIEW_RATING_STYLE_THUMBS_UP_DOWN
+         * @see android.support.media.tv.TvContractCompat.Programs#REVIEW_RATING_STYLE_PERCENTAGE
          */
         public T setReviewRating(String reviewRating) {
             mValues.put(ProgramColumns.COLUMN_REVIEW_RATING, reviewRating);
@@ -881,7 +887,7 @@
          *
          * @param seasonTitle The season title for the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
-         * @see Programs#COLUMN_SEASON_TITLE
+         * @see android.support.media.tv.TvContractCompat.Programs#COLUMN_SEASON_TITLE
          */
         public T setSeasonTitle(String seasonTitle) {
             mValues.put(ProgramColumns.COLUMN_SEASON_TITLE, seasonTitle);
diff --git a/tv-provider/src/main/java/android/support/media/tv/PreviewProgram.java b/tv-provider/src/main/java/android/support/media/tv/PreviewProgram.java
index 6d2fbaf..2536f75 100644
--- a/tv-provider/src/main/java/android/support/media/tv/PreviewProgram.java
+++ b/tv-provider/src/main/java/android/support/media/tv/PreviewProgram.java
@@ -19,12 +19,9 @@
 
 import android.content.ContentValues;
 import android.database.Cursor;
-import android.media.tv.TvContentRating;  // For javadoc gen of super class
 import android.os.Build;
 import android.support.annotation.RestrictTo;
 import android.support.media.tv.TvContractCompat.PreviewPrograms;
-import android.support.media.tv.TvContractCompat.Programs;  // For javadoc gen of super class
-import android.support.media.tv.TvContractCompat.Programs.Genres;  // For javadoc gen of super class
 
 /**
  * A convenience class to access {@link PreviewPrograms} entries in the system content
diff --git a/tv-provider/src/main/java/android/support/media/tv/Program.java b/tv-provider/src/main/java/android/support/media/tv/Program.java
index 882916d..d4de834 100644
--- a/tv-provider/src/main/java/android/support/media/tv/Program.java
+++ b/tv-provider/src/main/java/android/support/media/tv/Program.java
@@ -19,7 +19,6 @@
 
 import android.content.ContentValues;
 import android.database.Cursor;
-import android.media.tv.TvContentRating;  // For javadoc gen of super class
 import android.os.Build;
 import android.support.annotation.NonNull;
 import android.support.annotation.RestrictTo;
diff --git a/tv-provider/src/main/java/android/support/media/tv/WatchNextProgram.java b/tv-provider/src/main/java/android/support/media/tv/WatchNextProgram.java
index 61082aa..e5d12b2 100644
--- a/tv-provider/src/main/java/android/support/media/tv/WatchNextProgram.java
+++ b/tv-provider/src/main/java/android/support/media/tv/WatchNextProgram.java
@@ -19,13 +19,9 @@
 
 import android.content.ContentValues;
 import android.database.Cursor;
-import android.media.tv.TvContentRating;  // For javadoc gen of super class
 import android.os.Build;
 import android.support.annotation.IntDef;
 import android.support.annotation.RestrictTo;
-import android.support.media.tv.TvContractCompat.PreviewPrograms;  // For javadoc gen of super class
-import android.support.media.tv.TvContractCompat.Programs;  // For javadoc gen of super class
-import android.support.media.tv.TvContractCompat.Programs.Genres;  // For javadoc gen of super class
 import android.support.media.tv.TvContractCompat.WatchNextPrograms;
 
 import java.lang.annotation.Retention;
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/values-as/strings.xml b/v7/appcompat/res/values-as/strings.xml
new file mode 100644
index 0000000..1f90618
--- /dev/null
+++ b/v7/appcompat/res/values-as/strings.xml
@@ -0,0 +1,41 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_action_mode_done" msgid="4076576682505996667">"সম্পন্ন কৰা হ\'ল"</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_menu_overflow_description" msgid="3588849162933574182">"অধিক বিকল্প"</string>
+    <string name="abc_toolbar_collapse_description" msgid="1603543279005712093">"সংকুচিত কৰক"</string>
+    <string name="abc_searchview_description_search" msgid="8264924765203268293">"সন্ধান কৰক"</string>
+    <string name="abc_search_hint" msgid="7723749260725869598">"অনুসন্ধান কৰক…"</string>
+    <string name="abc_searchview_description_query" msgid="2550479030709304392">"সন্ধান কৰিব খোজা প্ৰশ্ন"</string>
+    <string name="abc_searchview_description_clear" msgid="3691816814315814921">"প্ৰশ্ন মচক"</string>
+    <string name="abc_searchview_description_submit" msgid="8928215447528550784">"প্ৰশ্ন দাখিল কৰক"</string>
+    <string name="abc_searchview_description_voice" msgid="893419373245838918">"কণ্ঠধ্বনিৰ যোগেৰে সন্ধান কৰক"</string>
+    <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"এটা এপ্ বাছনি কৰক"</string>
+    <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"সকলো চাওক"</string>
+    <!-- no translation found for abc_shareactionprovider_share_with_application (3300176832234831527) -->
+    <skip />
+    <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"ইয়াৰ জৰিয়তে শ্বেয়াৰ কৰক"</string>
+    <!-- no translation found for abc_capital_on (3405795526292276155) -->
+    <skip />
+    <!-- no translation found for abc_capital_off (121134116657445385) -->
+    <skip />
+    <!-- no translation found for search_menu_title (146198913615257606) -->
+    <skip />
+</resources>
diff --git a/v7/appcompat/res/values-or/strings.xml b/v7/appcompat/res/values-or/strings.xml
new file mode 100644
index 0000000..cf09b6e
--- /dev/null
+++ b/v7/appcompat/res/values-or/strings.xml
@@ -0,0 +1,42 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="abc_action_mode_done" msgid="4076576682505996667">"ହୋଇଗଲା"</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_menu_overflow_description" msgid="3588849162933574182">"ଅଧିକ ବିକଳ୍ପ"</string>
+    <!-- no translation found for abc_toolbar_collapse_description (1603543279005712093) -->
+    <skip />
+    <string name="abc_searchview_description_search" msgid="8264924765203268293">"ସର୍ଚ୍ଚ କରନ୍ତୁ"</string>
+    <string name="abc_search_hint" msgid="7723749260725869598">"ସର୍ଚ୍ଚ…"</string>
+    <string name="abc_searchview_description_query" msgid="2550479030709304392">"ସର୍ଚ୍ଚ କ୍ୱେରୀ"</string>
+    <string name="abc_searchview_description_clear" msgid="3691816814315814921">"କ୍ୱେରୀ ଖାଲି କରନ୍ତୁ"</string>
+    <string name="abc_searchview_description_submit" msgid="8928215447528550784">"କ୍ୱେରୀ ଦାଖଲ କରନ୍ତୁ"</string>
+    <string name="abc_searchview_description_voice" msgid="893419373245838918">"ଭଏସ୍‌ ସର୍ଚ୍ଚ"</string>
+    <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"ଗୋଟିଏ ଆପ୍‍ ବାଛନ୍ତୁ"</string>
+    <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"ସବୁ ଦେଖନ୍ତୁ"</string>
+    <!-- no translation found for abc_shareactionprovider_share_with_application (3300176832234831527) -->
+    <skip />
+    <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"ଏହାଙ୍କ ସହ ଶେୟାର୍‌ କରନ୍ତୁ"</string>
+    <!-- no translation found for abc_capital_on (3405795526292276155) -->
+    <skip />
+    <!-- no translation found for abc_capital_off (121134116657445385) -->
+    <skip />
+    <!-- no translation found for search_menu_title (146198913615257606) -->
+    <skip />
+</resources>
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/themes_base.xml b/v7/appcompat/res/values/themes_base.xml
index f628499..def6423 100644
--- a/v7/appcompat/res/values/themes_base.xml
+++ b/v7/appcompat/res/values/themes_base.xml
@@ -316,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. -->
@@ -487,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/tests/src/android/support/v7/widget/AppCompatEditTextTest.java b/v7/appcompat/src/androidTest/java/android/support/v7/widget/AppCompatEditTextTest.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/widget/AppCompatEditTextTest.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/widget/AppCompatEditTextTest.java
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/AndroidManifest.xml b/v7/appcompat/src/main/AndroidManifest.xml
similarity index 100%
rename from v7/appcompat/AndroidManifest.xml
rename to v7/appcompat/src/main/AndroidManifest.xml
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 92513dd..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
@@ -339,13 +339,15 @@
     public void setGroupDividerEnabled(boolean groupDividerEnabled) {
         // If mHasListDivider is true, disabling the groupDivider.
         // Otherwise, checking enbling it according to groupDividerEnabled flag.
-        mGroupDivider.setVisibility(!mHasListDivider
-                && groupDividerEnabled ? View.VISIBLE : View.GONE);
+        if (mGroupDivider != null) {
+            mGroupDivider.setVisibility(!mHasListDivider
+                    && groupDividerEnabled ? View.VISIBLE : View.GONE);
+        }
     }
 
     @Override
     public void adjustListItemSelectionBounds(Rect rect) {
-        if (mGroupDivider.getVisibility() == View.VISIBLE) {
+        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,
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/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/src/main/java/android/support/v7/widget/CardView.java b/v7/cardview/src/main/java/android/support/v7/widget/CardView.java
index a45ee98..d8511e9 100644
--- a/v7/cardview/src/main/java/android/support/v7/widget/CardView.java
+++ b/v7/cardview/src/main/java/android/support/v7/widget/CardView.java
@@ -26,6 +26,7 @@
 import android.support.annotation.ColorInt;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
+import android.support.annotation.Px;
 import android.support.v7.cardview.R;
 import android.util.AttributeSet;
 import android.view.View;
@@ -220,7 +221,7 @@
      * @attr ref android.support.v7.cardview.R.styleable#CardView_contentPaddingRight
      * @attr ref android.support.v7.cardview.R.styleable#CardView_contentPaddingBottom
      */
-    public void setContentPadding(int left, int top, int right, int bottom) {
+    public void setContentPadding(@Px int left, @Px int top, @Px int right, @Px int bottom) {
         mContentPadding.set(left, top, right, bottom);
         IMPL.updatePadding(mCardViewDelegate);
     }
@@ -306,6 +307,7 @@
      *
      * @return the inner padding after the Card's left edge
      */
+    @Px
     public int getContentPaddingLeft() {
         return mContentPadding.left;
     }
@@ -315,6 +317,7 @@
      *
      * @return the inner padding before the Card's right edge
      */
+    @Px
     public int getContentPaddingRight() {
         return mContentPadding.right;
     }
@@ -324,6 +327,7 @@
      *
      * @return the inner padding after the Card's top edge
      */
+    @Px
     public int getContentPaddingTop() {
         return mContentPadding.top;
     }
@@ -333,6 +337,7 @@
      *
      * @return the inner padding before the Card's bottom edge
      */
+    @Px
     public int getContentPaddingBottom() {
         return mContentPadding.bottom;
     }
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/AndroidManifest.xml b/v7/gridlayout/src/main/AndroidManifest.xml
similarity index 100%
rename from v7/gridlayout/AndroidManifest.xml
rename to v7/gridlayout/src/main/AndroidManifest.xml
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/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-af/strings.xml b/v7/mediarouter/res/values-af/strings.xml
deleted file mode 100644
index 8b47105..0000000
--- a/v7/mediarouter/res/values-af/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">"Stelsel"</string>
-    <string name="mr_user_route_category_name" msgid="7498112907524977311">"Toestelle"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Cast-knoppie"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Uitsaai-knoppie. Ontkoppel"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Uitsaai-knoppie. Koppel tans"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Uitsaai-knoppie. Gekoppel"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Saai uit na"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Vind tans toestelle"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Ontkoppel"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Hou op uitsaai"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Maak toe"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Speel"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"Laat wag"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Stop"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Vou uit"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Vou in"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Albumkunswerk"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Volumeglyer"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Geen media is gekies nie"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Geen inligting beskikbaar nie"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Saai tans skerm uit"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-am/strings.xml b/v7/mediarouter/res/values-am/strings.xml
deleted file mode 100644
index 9959767..0000000
--- a/v7/mediarouter/res/values-am/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">"የCast አዝራር"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Cast አዝራር። ግንኙነት ተቋርጧል"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Cast አዝራር በማገናኘት ላይ"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Cast አዝራር። ተገናኝቷል"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Cast አድርግ ወደ"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"መሣሪያዎችን በማግኘት ላይ"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"ግንኙነት አቋርጥ"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Cast ማድረግ አቁም"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"ዝጋ"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"አጫውት"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"ለአፍታ አቁም"</string>
-    <string name="mr_controller_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-ar/strings.xml b/v7/mediarouter/res/values-ar/strings.xml
deleted file mode 100644
index 864fb91..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-az/strings.xml b/v7/mediarouter/res/values-az/strings.xml
deleted file mode 100644
index 0255164..0000000
--- a/v7/mediarouter/res/values-az/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ım düyməsi"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Yayım düyməsi. Bağlantı kəsildi"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Yayım düyməsi. Qoşulur"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Yayım düyməsi. Qoşuldu"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Bura yayımlayın"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Cihazlar axtarılır"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Bağlantını kəsin"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Yayımı dayandırın"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Qapadın"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Oynadın"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"Durdurun"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Dayandırın"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Genişləndirin"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Yığcamlaşdırın"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Albom incəsənəti"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Səs hərmi diyircəyi"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Heç bir media seçilməyib"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Əlçatan məlumat yoxdur"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Ekran yayımlanır"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-b+sr+Latn/strings.xml b/v7/mediarouter/res/values-b+sr+Latn/strings.xml
deleted file mode 100644
index c4bfa49..0000000
--- a/v7/mediarouter/res/values-b+sr+Latn/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">"Uređaji"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Dugme Prebaci"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Dugme Prebaci. Veza je prekinuta"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Dugme Prebaci. Povezuje se"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Dugme Prebaci. Povezan je"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Prebacuj na"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Pronalaženje uređaja"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Prekini vezu"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Zaustavi prebacivanje"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Zatvori"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Pusti"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"Pauziraj"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Zaustavi"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Proširi"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Skupi"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Omot albuma"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Klizač za jačinu zvuka"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nema izabranih medija"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nisu dostupne nikakve informacije"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Prebacuje se ekran"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-be/strings.xml b/v7/mediarouter/res/values-be/strings.xml
deleted file mode 100644
index 396088f..0000000
--- a/v7/mediarouter/res/values-be/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-bg/strings.xml b/v7/mediarouter/res/values-bg/strings.xml
deleted file mode 100644
index 6d32abb..0000000
--- a/v7/mediarouter/res/values-bg/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-bn/strings.xml b/v7/mediarouter/res/values-bn/strings.xml
deleted file mode 100644
index b827751..0000000
--- a/v7/mediarouter/res/values-bn/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-bs/strings.xml b/v7/mediarouter/res/values-bs/strings.xml
deleted file mode 100644
index ab9575e..0000000
--- a/v7/mediarouter/res/values-bs/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">"Uređaji"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Dugme za emitiranje"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Dugme za emitiranje. Veza je prekinuta"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Dugme za emitiranje. Povezivanje"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Dugme za emitiranje. Povezano"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Emitiranje na"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Traženje uređaja"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Prekini vezu"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Zaustavi prebacivanje"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Zatvori"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Reproduciraj"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"Pauziraj"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Zaustavi"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Proširi"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Skupi"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Omot albuma"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Klizač za jačinu zvuka"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nijedan medij nije odabran"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nema dostupnih informacija"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Prebacuje se ekran"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-ca/strings.xml b/v7/mediarouter/res/values-ca/strings.xml
deleted file mode 100644
index 7e01048..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\'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/res/values-cs/strings.xml
deleted file mode 100644
index b36cf26..0000000
--- a/v7/mediarouter/res/values-cs/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">"Systém"</string>
-    <string name="mr_user_route_category_name" msgid="7498112907524977311">"Zařízení"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Tlačítko odesílání"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Tlačítko odesílání. Odpojeno"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Tlačítko odesílání. Připojování"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Tlačítko odesílání. Připojeno"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Odesílat do"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Hledání zařízení"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Odpojit"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Zastavit odesílání"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Zavřít"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Přehrát"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"Pozastavit"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Zastavit"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Rozbalit"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Sbalit"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Obal alba"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Posuvník hlasitosti"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nebyla vybrána žádná média"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nejsou k dispozici žádné informace"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Odesílání obsahu obrazovky"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-da/strings.xml b/v7/mediarouter/res/values-da/strings.xml
deleted file mode 100644
index d280d2c..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">"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/res/values-de/strings.xml
deleted file mode 100644
index edbb89a..0000000
--- a/v7/mediarouter/res/values-de/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">"Geräte"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Cast-Symbol"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Streaming-Schaltfläche. Nicht verbunden"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Streaming-Schaltfläche. Verbindung wird hergestellt"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Streaming-Schaltfläche. Verbunden"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Streamen auf"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Geräte werden gesucht."</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Verbindung trennen"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Streaming beenden"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Schließen"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Wiedergeben"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"Pausieren"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Beenden"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Maximieren"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Minimieren"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Albumcover"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Schieberegler für die Lautstärke"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Keine Medien ausgewählt"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Keine Informationen verfügbar"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Bildschirm wird gestreamt."</string>
-</resources>
diff --git a/v7/mediarouter/res/values-el/strings.xml b/v7/mediarouter/res/values-el/strings.xml
deleted file mode 100644
index dc7bd0f..0000000
--- a/v7/mediarouter/res/values-el/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">"Κουμπί Cast"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Κουμπί μετάδοσης. Αποσυνδέθηκε"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Κουμπί μετάδοση. Σύνδεση σε εξέλιξη"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Κουμπί μετάδοσης. Συνδέθηκε"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Μετάδοση σε"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Εύρεση συσκευών"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Αποσύνδεση"</string>
-    <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-en-rAU/strings.xml b/v7/mediarouter/res/values-en-rAU/strings.xml
deleted file mode 100644
index cbc5135..0000000
--- a/v7/mediarouter/res/values-en-rAU/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">"Devices"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Cast button"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Cast button. Disconnected"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Cast button. Connecting"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Cast button. Connected"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Cast to"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Finding devices"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Disconnect"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Stop casting"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Close"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Play"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"Pause"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Stop"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Expand"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Collapse"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Album art"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Volume slider"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"No media selected"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"No info available"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Casting screen"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-en-rCA/strings.xml b/v7/mediarouter/res/values-en-rCA/strings.xml
deleted file mode 100644
index cbc5135..0000000
--- a/v7/mediarouter/res/values-en-rCA/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">"Devices"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Cast button"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Cast button. Disconnected"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Cast button. Connecting"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Cast button. Connected"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Cast to"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Finding devices"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Disconnect"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Stop casting"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Close"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Play"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"Pause"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Stop"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Expand"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Collapse"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Album art"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Volume slider"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"No media selected"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"No info available"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Casting screen"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-en-rGB/strings.xml b/v7/mediarouter/res/values-en-rGB/strings.xml
deleted file mode 100644
index cbc5135..0000000
--- a/v7/mediarouter/res/values-en-rGB/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">"Devices"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Cast button"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Cast button. Disconnected"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Cast button. Connecting"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Cast button. Connected"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Cast to"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Finding devices"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Disconnect"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Stop casting"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Close"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Play"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"Pause"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Stop"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Expand"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Collapse"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Album art"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Volume slider"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"No media selected"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"No info available"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Casting screen"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-en-rIN/strings.xml b/v7/mediarouter/res/values-en-rIN/strings.xml
deleted file mode 100644
index cbc5135..0000000
--- a/v7/mediarouter/res/values-en-rIN/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">"Devices"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Cast button"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Cast button. Disconnected"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Cast button. Connecting"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Cast button. Connected"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Cast to"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Finding devices"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Disconnect"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Stop casting"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Close"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Play"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"Pause"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Stop"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Expand"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Collapse"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Album art"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Volume slider"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"No media selected"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"No info available"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Casting screen"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-en-rXC/strings.xml b/v7/mediarouter/res/values-en-rXC/strings.xml
deleted file mode 100644
index 8ed9aab..0000000
--- a/v7/mediarouter/res/values-en-rXC/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">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‎‎‏‏‏‎‏‎‏‎‎‏‎‏‏‏‏‏‎‏‏‎‎‏‏‏‎‎‏‎‏‏‎‎‏‏‎‎‎‎‏‏‎‎‏‎‏‎‎‏‏‏‏‏‎Devices‎‏‎‎‏‎"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‏‎‏‎‏‎‎‏‏‎‏‎‎‎‏‏‏‎‏‎‎‎‏‏‎‎‎‏‏‎‏‏‏‎‎‏‏‏‏‏‎‏‏‏‏‏‎‏‎‎‎‎‏‎‎‎‏‎Cast button‎‏‎‎‏‎"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‏‎‏‎‏‎‏‎‎‎‎‎‏‏‎‎‏‏‎‎‎‎‏‎‎‏‏‎‎‎‎‎‏‎‎‏‎‎‏‏‎‏‎‏‏‎‏‎‎‏‏‏‎‏‎‎‎‎Cast button. Disconnected‎‏‎‎‏‎"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‎‏‏‎‎‎‎‎‎‏‎‎‎‏‎‏‎‎‏‏‎‎‎‎‎‏‎‎‏‎‎‏‎‎‎‎‏‎‏‎‏‎‎Cast button. Connecting‎‏‎‎‏‎"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‏‎‎‏‏‏‎‏‏‎‏‏‏‎‏‎‎‎‎‏‏‎‎‏‎‏‎‎‏‎‏‎‏‎‏‏‎‎‎‏‏‏‎‏‏‏‏‎‏‎‎‏‎‏‎‏‎Cast button. Connected‎‏‎‎‏‎"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‏‎‏‎‏‏‏‎‏‏‎‏‏‏‏‎‎‏‏‏‎‎‏‎‏‏‎‎‎‏‏‎‏‏‎‏‏‎‎Cast to‎‏‎‎‏‎"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‎‏‏‏‎‏‏‏‏‎‎‎‏‎‎‎‎‏‎‎‏‎‏‏‏‏‏‎‎‏‎‎‏‏‎‏‎‎‏‎‎‎Finding devices‎‏‎‎‏‎"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‏‎‎‎‎‏‎‎‎‎‎‎‏‏‏‏‎‏‏‏‎‏‎‏‎‎‎‏‎‎‎‏‎‏‏‎‎‎‏‎‏‎‎‏‏‎‎‏‎‏‎‎‎‏‏‎‎‎Disconnect‎‏‎‎‏‎"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‏‏‎‏‏‎‎‎‏‎‎‏‎‎‎‏‏‎‏‏‏‎‏‎‏‏‏‎‎‎‏‎‎‏‏‏‏‎‎‎‏‎‏‏‏‎‏‏‏‎‏‎‎Stop casting‎‏‎‎‏‎"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‎‎‎‏‏‏‎‎‎‏‏‏‎‎‏‏‏‎‏‎‏‎‏‎‏‎‏‏‏‏‎‎‎‎‎‏‏‏‏‎‏‎‏‏‏‎‎‏‎‏‏‏‎‎‎Close‎‏‎‎‏‎"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‏‎‏‏‏‏‏‎‎‏‏‎‎‎‎‏‎‎‎‎‎‎‏‎‎‎‎‎‎‎‏‎‎‏‏‎‏‎‎‎‏‏‏‎‎‎‏‏‏‏‎‎‎‎‎‏‎‎Play‎‏‎‎‏‎"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‎‏‎‏‎‎‎‏‏‏‏‏‏‎‎‎‎‎‎‎‎‏‎‎‎‏‏‏‏‏‏‎‎‎‏‏‎‏‏‏‏‎‎‏‎‏‎‎‎‏‏‏‏‏‎‎Pause‎‏‎‎‏‎"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‎‎‎‏‏‎‏‏‎‎‏‎‏‏‎‏‎‎‎‎‏‎‏‏‎‏‎‎‎‎‏‏‎‏‏‏‏‎‎‎‏‏‎‏‏‏‏‏‎‏‏‏‎‎‎‏‏‎Stop‎‏‎‎‏‎"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‎‏‎‏‎‎‏‎‎‎‏‏‏‏‎‎‎‏‎‏‏‏‎‏‎‏‎‏‎‎‎‏‎‎‏‏‎‏‏‎Expand‎‏‎‎‏‎"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‏‏‎‏‎‏‎‎‏‎‎‏‏‏‏‎‏‏‎‎‏‏‎‎‎‏‏‎‏‏‎‎‏‎‎‏‏‎‏‎‏‏‏‏‏‎‎‎‏‏‏‏‎‎Collapse‎‏‎‎‏‎"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‎‎‎‏‎‎‏‏‎‎‎‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‎‏‏‏‏‎‏‎‏‎‏‎‎‏‎‎‎‎‏‏‎‎‎‎‏‎Album art‎‏‎‎‏‎"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‏‏‎‎‎‏‏‎‏‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‎‏‏‏‏‎‏‎‏‎‎‎‏‏‏‏‏‎‎‎‎‏‎‏‎‏‎‏‏‎‏‎Volume slider‎‏‎‎‏‎"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‏‎‏‏‏‎‎‎‎‎‏‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎‏‎‏‏‎‏‎No media selected‎‏‎‎‏‎"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‏‏‎‎‎‎‎‏‏‎‏‏‎‎‏‎‎‏‎‎‎‎‎‎‏‏‏‎‏‏‎‏‎‎‎‎‎‏‎‎‏‎‎‏‏‎‏‏‏‏‎‎‎‏‏‎‎‎No info available‎‏‎‎‏‎"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‎‏‎‎‎‎‎‎‏‏‏‏‎‎‏‎‏‏‎‏‏‏‏‏‎‎‎‎‏‏‏‏‏‎‏‎‏‎‏‎‏‎‏‏‎‏‏‎‎‎‎‎‏‏‎Casting screen‎‏‎‎‏‎"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-es-rUS/strings.xml b/v7/mediarouter/res/values-es-rUS/strings.xml
deleted file mode 100644
index fc2a067..0000000
--- a/v7/mediarouter/res/values-es-rUS/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">"Dispositivos"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Botón para transmitir"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Botón para transmitir (desconectado)"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Botón para transmitir (conectando)"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Botón para transmitir (conectado)"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Transmitir a"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Buscando dispositivos"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Desconectar"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Detener la transmisión"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Cerrar"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Reproducir"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"Pausar"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Detener"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Mostrar"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Ocultar"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Imagen del álbum"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Control deslizante del volumen"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"No se seleccionó ningún contenido multimedia"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Sin información disponible"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Transmitiendo pantalla"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-es/strings.xml b/v7/mediarouter/res/values-es/strings.xml
deleted file mode 100644
index 34c1804..0000000
--- a/v7/mediarouter/res/values-es/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">"Dispositivos"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Botón de enviar"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Botón de enviar. Desconectado"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Botón de enviar. Conectando"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Botón de enviar. Conectado"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Enviar a"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Buscando dispositivos"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Desconectar"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Detener envío de contenido"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Cerrar"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Reproducir"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"Pausa"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Detener"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Mostrar"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Ocultar"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Portada del álbum"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Control deslizante de volumen"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"No se ha seleccionado ningún medio"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"No hay información disponible"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Enviando pantalla"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-et/strings.xml b/v7/mediarouter/res/values-et/strings.xml
deleted file mode 100644
index 2fc7834..0000000
--- a/v7/mediarouter/res/values-et/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">"Süsteem"</string>
-    <string name="mr_user_route_category_name" msgid="7498112907524977311">"Seadmed"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Ülekandenupp"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Ülekandenupp. Ühendus on katkestatud"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Ülekandenupp. Ühendamine"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Ülekandenupp. Ühendatud"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Ülekandmine seadmesse"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Seadmete otsimine"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Katkesta ühendus"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Peata ülekandmine"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Sulgemine"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Esitamine"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"Peatamine"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Peata"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Laiendamine"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Ahendamine"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Albumi kujundus"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Helitugevuse liugur"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Meediat pole valitud"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Teave puudub"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Ekraanikuva ülekandmine"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-eu/strings.xml b/v7/mediarouter/res/values-eu/strings.xml
deleted file mode 100644
index 11b1d00..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-fa/strings.xml b/v7/mediarouter/res/values-fa/strings.xml
deleted file mode 100644
index 8e8e532..0000000
--- a/v7/mediarouter/res/values-fa/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-fi/strings.xml b/v7/mediarouter/res/values-fi/strings.xml
deleted file mode 100644
index 5ba0a2e..0000000
--- a/v7/mediarouter/res/values-fi/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">"Järjestelmä"</string>
-    <string name="mr_user_route_category_name" msgid="7498112907524977311">"Laitteet"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Cast-painike"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Cast-painike. Yhteys katkaistu"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Cast-painike. Yhdistetään"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Cast-painike. Yhdistetty"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Suoratoiston kohde"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Etsitään laitteita"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Katkaise yhteys"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Lopeta suoratoisto"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Sulje"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Toista"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"Keskeytä"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Pysäytä"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Laajenna"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Tiivistä"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Albumin kansikuva"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Äänenvoimakkuuden liukusäädin"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Ei valittua mediaa."</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Tietoja ei ole saatavilla"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Suoratoistetaan näyttöä"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-fr-rCA/strings.xml b/v7/mediarouter/res/values-fr-rCA/strings.xml
deleted file mode 100644
index f81b136..0000000
--- a/v7/mediarouter/res/values-fr-rCA/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">"Système"</string>
-    <string name="mr_user_route_category_name" msgid="7498112907524977311">"Appareils"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Bouton Diffuser"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Bouton Diffuser. Déconnecté"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Bouton Diffuser. Connexion en cours…"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Bouton Diffuser. Connecté"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Diffuser sur"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Recherche d\'appareils"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Se déconnecter"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Arrêter la diffusion"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Fermer"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Lire"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"Interrompre"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Arrêter"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Développer"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Réduire"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Image de l\'album"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Curseur de réglage du volume"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Aucun média sélectionné"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Aucune information disponible"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Diffusion de l\'écran en cours"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-fr/strings.xml b/v7/mediarouter/res/values-fr/strings.xml
deleted file mode 100644
index 47a7c6b..0000000
--- a/v7/mediarouter/res/values-fr/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">"Système"</string>
-    <string name="mr_user_route_category_name" msgid="7498112907524977311">"Appareils"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Icône Cast"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Icône Cast. Déconnecté"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Icône Cast. Connexion…"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Icône Cast. Connecté"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Caster sur"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Recherche d\'appareils…"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Déconnecter"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Arrêter la diffusion"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Fermer"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Lecture"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"Pause"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Arrêter"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Développer"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Réduire"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Image de l\'album"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Curseur de volume"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Aucun média sélectionné"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Aucune information disponible"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Diffusion de l\'écran en cours…"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-gl/strings.xml b/v7/mediarouter/res/values-gl/strings.xml
deleted file mode 100644
index e509ab7..0000000
--- a/v7/mediarouter/res/values-gl/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">"Dispositivos"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Botón de emitir"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Botón de emitir. Desconectado"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Botón de emitir. Conectando"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Botón de emitir. Conectado"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Emitir a"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Buscando dispositivos"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Desconectar"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Deter emisión"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Pechar"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Reproduce"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"Pausa"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Deter"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Ampliar"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Contraer"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Portada do álbum"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Control desprazable do volume"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Non se seleccionaron recursos"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Non hai información dispoñible"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Emisión de pantalla"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-gu/strings.xml b/v7/mediarouter/res/values-gu/strings.xml
deleted file mode 100644
index 2792842..0000000
--- a/v7/mediarouter/res/values-gu/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-hi/strings.xml b/v7/mediarouter/res/values-hi/strings.xml
deleted file mode 100644
index f9ac43b..0000000
--- a/v7/mediarouter/res/values-hi/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-hr/strings.xml b/v7/mediarouter/res/values-hr/strings.xml
deleted file mode 100644
index e19b56c..0000000
--- a/v7/mediarouter/res/values-hr/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">"Sustav"</string>
-    <string name="mr_user_route_category_name" msgid="7498112907524977311">"Uređaji"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Gumb za emitiranje"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Gumb za emitiranje. Veza prekinuta"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Gumb za emitiranje. Povezivanje"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Gumb za emitiranje. Povezan"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Emitiranje na"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Traženje uređaja"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Prekini vezu"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Zaustavi emitiranje"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Zatvaranje"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Reprodukcija"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"Pauziranje"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Zaustavi"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Proširivanje"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Sažimanje"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Naslovnica albuma"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Klizač za glasnoću"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nije odabran nijedan medij"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Informacije nisu dostupne"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Emitiranje zaslona"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-hu/strings.xml b/v7/mediarouter/res/values-hu/strings.xml
deleted file mode 100644
index 715fa43..0000000
--- a/v7/mediarouter/res/values-hu/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">"Rendszer"</string>
-    <string name="mr_user_route_category_name" msgid="7498112907524977311">"Eszközök"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Átküldés gomb"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Átküldés gomb. Kapcsolat bontva"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Átküldés gomb. Csatlakozás"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Átküldés gomb. Csatlakoztatva"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Átküldés ide"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Eszközök keresése"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Leválasztás"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Átküldés leállítása"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Bezárás"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Lejátszás"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"Szüneteltetés"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Leállítás"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Kibontás"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Összecsukás"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Lemezborító"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Hangerőszabályzó"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nincs média kiválasztva"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nincs információ"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Képernyőtartalom átküldése"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-hy/strings.xml b/v7/mediarouter/res/values-hy/strings.xml
deleted file mode 100644
index f7547af..0000000
--- a/v7/mediarouter/res/values-hy/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-in/strings.xml b/v7/mediarouter/res/values-in/strings.xml
deleted file mode 100644
index becb41e..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 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/res/values-is/strings.xml
deleted file mode 100644
index 86f009e..0000000
--- a/v7/mediarouter/res/values-is/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">"Kerfi"</string>
-    <string name="mr_user_route_category_name" msgid="7498112907524977311">"Tæki"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Útsendingarhnappur"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Útsendingarhnappur. Aftengt"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Útsendingarhnappur. Tengist"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Útsendingarhnappur. Tengt"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Senda út í"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Leitað að tækjum"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Aftengjast"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Stöðva útsendingu"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Loka"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Spila"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"Hlé"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Stöðva"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Stækka"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Minnka"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Plötuumslag"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Hljóðstyrkssleði"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Enginn miðill valinn"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Engar upplýsingar í boði"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Skjár sendur út"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-it/strings.xml b/v7/mediarouter/res/values-it/strings.xml
deleted file mode 100644
index dfff161..0000000
--- a/v7/mediarouter/res/values-it/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">"Dispositivi"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Pulsante Trasmetti"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Pulsante Trasmetti. Disconnesso"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Pulsante Trasmetti. Connessione in corso"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Pulsante Trasmetti. Connesso"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Trasmetti a"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Ricerca di dispositivi in corso"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Scollega"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Interrompi trasmissione"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Chiudi"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Riproduci"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"Pausa"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Interrompi"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Espandi"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Comprimi"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Copertina"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Dispositivo di scorrimento del volume"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nessun contenuto multimediale selezionato"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nessuna informazione disponibile"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Trasmissione dello schermo in corso"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-iw/strings.xml b/v7/mediarouter/res/values-iw/strings.xml
deleted file mode 100644
index 02f50ff..0000000
--- a/v7/mediarouter/res/values-iw/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">"‏לחצן הפעלת Cast"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"‏לחצן הפעלת Cast. מנותק"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"‏לחצן הפעלת Cast. מתחבר"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"‏לחצן הפעלת Cast. מחובר"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"העברה אל"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"מחפש מכשירים"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"נתק"</string>
-    <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-ja/strings.xml b/v7/mediarouter/res/values-ja/strings.xml
deleted file mode 100644
index b029c44..0000000
--- a/v7/mediarouter/res/values-ja/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-ka/strings.xml b/v7/mediarouter/res/values-ka/strings.xml
deleted file mode 100644
index 22480ca..0000000
--- a/v7/mediarouter/res/values-ka/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-kk/strings.xml b/v7/mediarouter/res/values-kk/strings.xml
deleted file mode 100644
index 8128074..0000000
--- a/v7/mediarouter/res/values-kk/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-km/strings.xml b/v7/mediarouter/res/values-km/strings.xml
deleted file mode 100644
index f9f339d..0000000
--- a/v7/mediarouter/res/values-km/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-kn/strings.xml b/v7/mediarouter/res/values-kn/strings.xml
deleted file mode 100644
index cd0ff44..0000000
--- a/v7/mediarouter/res/values-kn/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-ko/strings.xml b/v7/mediarouter/res/values-ko/strings.xml
deleted file mode 100644
index 2d3f837..0000000
--- a/v7/mediarouter/res/values-ko/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-ky/strings.xml b/v7/mediarouter/res/values-ky/strings.xml
deleted file mode 100644
index e90a960..0000000
--- a/v7/mediarouter/res/values-ky/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-lo/strings.xml b/v7/mediarouter/res/values-lo/strings.xml
deleted file mode 100644
index d50ae66..0000000
--- a/v7/mediarouter/res/values-lo/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-lt/strings.xml b/v7/mediarouter/res/values-lt/strings.xml
deleted file mode 100644
index 6545f9a..0000000
--- a/v7/mediarouter/res/values-lt/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">"Įrenginiai"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Perdavimo mygtukas"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Perdavimo mygtukas. Atsijungta"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Perdavimo mygtukas. Prisijungiama"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Perdavimo mygtukas. Prisijungta"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Perduoti į"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Randami įrenginiai"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Atjungti"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Sustabdyti perdavimą"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Uždaryti"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Leisti"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"Pristabdyti"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Sustabdyti"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Išskleisti"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Sutraukti"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Albumo viršelis"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Garsumo šliaužiklis"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nepasirinkta jokia medija"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Informacija nepasiekiama"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Perduodamas ekranas"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-lv/strings.xml b/v7/mediarouter/res/values-lv/strings.xml
deleted file mode 100644
index 46b69b3..0000000
--- a/v7/mediarouter/res/values-lv/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">"Sistēma"</string>
-    <string name="mr_user_route_category_name" msgid="7498112907524977311">"Ierīces"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Apraides poga"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Apraides poga. Savienojums pārtraukts"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Apraides poga. Notiek savienojuma izveide"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Apraides poga. Savienojums izveidots"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Apraidīšana uz ierīci"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Notiek ierīču meklēšana"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Atvienot"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Apturēt apraidi"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Aizvērt"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Atskaņot"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"Apturēt"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Apturēt"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Izvērst"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Sakļaut"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Albuma vāciņš"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Skaļuma slīdnis"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nav atlasīti multivides faili"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nav pieejama informācija"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Notiek ekrāna apraide"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-mk/strings.xml b/v7/mediarouter/res/values-mk/strings.xml
deleted file mode 100644
index d5b9365..0000000
--- a/v7/mediarouter/res/values-mk/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">"Копчето за Cast"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Копче за Cast. Исклучено"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Копче за Cast. Се поврзува"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Копче за Cast. Поврзано"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Емитувај на"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Се бараат уреди"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Исклучи"</string>
-    <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-ml/strings.xml b/v7/mediarouter/res/values-ml/strings.xml
deleted file mode 100644
index 62258fb..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-mn/strings.xml b/v7/mediarouter/res/values-mn/strings.xml
deleted file mode 100644
index debccf9..0000000
--- a/v7/mediarouter/res/values-mn/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 596b56a..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-ms/strings.xml b/v7/mediarouter/res/values-ms/strings.xml
deleted file mode 100644
index 4f305b0..0000000
--- a/v7/mediarouter/res/values-ms/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">"Peranti"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Butang Hantar"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Butang hantar. Sambungan diputuskan"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Butang hantar. Menyambung"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Butang hantar. Disambungkan"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Hantar ke"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Mencari peranti"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Putuskan sambungan"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Berhenti menghantar"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Tutup"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Main"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"Jeda"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Berhenti"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Kembangkan"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Runtuhkan"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Seni album"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Peluncur kelantangan"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Tiada media dipilih"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Maklumat tidak tersedia"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Menghantar skrin"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-my/strings.xml b/v7/mediarouter/res/values-my/strings.xml
deleted file mode 100644
index fb0074d..0000000
--- a/v7/mediarouter/res/values-my/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-nb/strings.xml b/v7/mediarouter/res/values-nb/strings.xml
deleted file mode 100644
index 7c99442..0000000
--- a/v7/mediarouter/res/values-nb/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">"Enheter"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Cast-ikonet"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Cast-knappen. Frakoblet"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Cast-knappen. Kobler til"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Cast-knappen. Tilkoblet"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Cast til"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Søker etter enheter"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Koble fra"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Stopp castingen"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Lukk"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Spill av"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"Sett på pause"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Stopp"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Utvid"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Skjul"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Albumgrafikk"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Glidebryter for volum"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Du har ikke valgt noen medier"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Ingen informasjon er tilgjengelig"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Caster skjermen"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-ne/strings.xml b/v7/mediarouter/res/values-ne/strings.xml
deleted file mode 100644
index 0622ca9..0000000
--- a/v7/mediarouter/res/values-ne/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">"Cast बटन"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Cast बटन। जडान विच्छेद भयो"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Cast बटन। जडान हुँदै"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Cast बटन। जडान भयो"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"यसमा Cast गर्नुहोस्"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"यन्त्रहरू पत्ता लगाउँदै"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"विच्छेद गर्नुहोस्"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"casting रोक्नुहोस्"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"बन्द गर्नुहोस्"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"बजाउनुहोस्"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"रोक्नुहोस्"</string>
-    <string name="mr_controller_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">"स्क्रिन cast गर्दै"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-nl/strings.xml b/v7/mediarouter/res/values-nl/strings.xml
deleted file mode 100644
index fcb674f..0000000
--- a/v7/mediarouter/res/values-nl/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">"Systeem"</string>
-    <string name="mr_user_route_category_name" msgid="7498112907524977311">"Apparaten"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Cast-icoon"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Cast-icoon. Verbinding verbroken"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Cast-icoon. Verbinding maken"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Cast-icoon. Verbonden"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Casten naar"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Apparaten zoeken"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Loskoppelen"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Casten stoppen"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Sluiten"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Afspelen"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"Onderbreken"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Stoppen"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Uitvouwen"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Samenvouwen"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Albumhoes"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Volumeschuifregelaar"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Geen media geselecteerd"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Geen informatie beschikbaar"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Scherm casten"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-pa/strings.xml b/v7/mediarouter/res/values-pa/strings.xml
deleted file mode 100644
index f1a1a30..0000000
--- a/v7/mediarouter/res/values-pa/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-pl/strings.xml b/v7/mediarouter/res/values-pl/strings.xml
deleted file mode 100644
index 7154e9d..0000000
--- a/v7/mediarouter/res/values-pl/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">"Urządzenia"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Przycisk Cast"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Przycisk Prześlij ekran. Rozłączono"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Przycisk Prześlij ekran. Łączę"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Przycisk Prześlij ekran. Połączono"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Przesyłaj na"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Znajdowanie urządzeń"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Odłącz"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Zatrzymaj przesyłanie"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Zamknij"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Odtwórz"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"Wstrzymaj"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Zatrzymaj"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Rozwiń"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Zwiń"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Okładka albumu"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Suwak głośności"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nie wybrano multimediów"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Brak informacji"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Przesyłam ekran"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-pt-rBR/strings.xml b/v7/mediarouter/res/values-pt-rBR/strings.xml
deleted file mode 100644
index d7fbbb8..0000000
--- a/v7/mediarouter/res/values-pt-rBR/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">"Dispositivos"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Botão Transmitir"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Botão \"Transmitir\". Desconectado"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Botão \"Transmitir\". Conectando"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Botão \"Transmitir\". Conectado"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Transmitir para"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Localizando dispositivos"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Desconectar"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Interromper transmissão"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Fechar"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Reproduzir"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"Pausar"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Parar"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Expandir"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Recolher"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Arte do álbum"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Controle deslizante de volume"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nenhuma mídia selecionada"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nenhuma informação disponível"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Transmitindo a tela"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-pt-rPT/strings.xml b/v7/mediarouter/res/values-pt-rPT/strings.xml
deleted file mode 100644
index 0e700df..0000000
--- a/v7/mediarouter/res/values-pt-rPT/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">"Dispositivos"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Botão Transmitir"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Botão Transmitir. Desligado"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Botão Transmitir. A ligar..."</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Botão Transmitir. Ligado"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Transmitir para"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"A localizar dispositivos"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Desassociar"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Parar a transmissão"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Fechar"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Reproduzir"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"Interromper"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Parar"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Expandir"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Reduzir"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Imagem do álbum"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Controlo de deslize do volume"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nenhum suporte multimédia selecionado"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nenhuma informação disponível"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"A transmitir o ecrã"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-pt/strings.xml b/v7/mediarouter/res/values-pt/strings.xml
deleted file mode 100644
index d7fbbb8..0000000
--- a/v7/mediarouter/res/values-pt/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">"Dispositivos"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Botão Transmitir"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Botão \"Transmitir\". Desconectado"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Botão \"Transmitir\". Conectando"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Botão \"Transmitir\". Conectado"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Transmitir para"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Localizando dispositivos"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Desconectar"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Interromper transmissão"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Fechar"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Reproduzir"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"Pausar"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Parar"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Expandir"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Recolher"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Arte do álbum"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Controle deslizante de volume"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nenhuma mídia selecionada"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nenhuma informação disponível"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Transmitindo a tela"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-ro/strings.xml b/v7/mediarouter/res/values-ro/strings.xml
deleted file mode 100644
index 0f213183..0000000
--- a/v7/mediarouter/res/values-ro/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">"Dispozitive"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Butonul de proiecție"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Butonul de proiecție. Deconectat"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Butonul de proiecție. Se conectează"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Butonul de proiecție. Conectat"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Proiectați pe"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Se caută dispozitive"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Deconectați-vă"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Nu mai proiectați"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Închideți"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Redați"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"Întrerupeți"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Opriți"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Extindeți"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Restrângeți"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Grafica albumului"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Glisor pentru volum"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Niciun fișier media selectat"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nu sunt disponibile informații"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Se proiectează ecranul"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-ru/strings.xml b/v7/mediarouter/res/values-ru/strings.xml
deleted file mode 100644
index 1ac86d8..0000000
--- a/v7/mediarouter/res/values-ru/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-si/strings.xml b/v7/mediarouter/res/values-si/strings.xml
deleted file mode 100644
index bb87945..0000000
--- a/v7/mediarouter/res/values-si/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-sk/strings.xml b/v7/mediarouter/res/values-sk/strings.xml
deleted file mode 100644
index 43a769a..0000000
--- a/v7/mediarouter/res/values-sk/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">"Systém"</string>
-    <string name="mr_user_route_category_name" msgid="7498112907524977311">"Zariadenia"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Tlačidlo prenosu"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Tlačidlo prenosu. Odpojené"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Tlačidlo prenosu. Pripája sa"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Tlačidlo prenosu. Pripojené"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Prenos do"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Hľadajú sa zariadenia"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Odpojiť"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Zastaviť prenášanie"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Zavrieť"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Prehrať"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"Pozastaviť"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Zastaviť"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Rozbaliť"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Zbaliť"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Obrázok albumu"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Posúvač hlasitosti"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nie sú vybrané žiadne médiá"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nie sú k dispozícii žiadne informácie"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Prenáša sa obrazovka"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-sl/strings.xml b/v7/mediarouter/res/values-sl/strings.xml
deleted file mode 100644
index abd82de..0000000
--- a/v7/mediarouter/res/values-sl/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">"Naprave"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Gumb za predvajanje"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Gumb za predvajanje. Povezava je prekinjena."</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Gumb za predvajanje. Vzpostavljanje povezave."</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Gumb za predvajanje. Povezava je vzpostavljena."</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Predvajanje prek:"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Iskanje naprav"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Prekini povezavo"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Ustavi predvajanje"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Zapri"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Predvajanje"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"Zaustavi"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Ustavi"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Razširi"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Strni"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Naslovnica albuma"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Drsnik za glasnost"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Ni izbrane predstavnosti"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Podatki niso na voljo"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Predvajanje zaslona"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-sq/strings.xml b/v7/mediarouter/res/values-sq/strings.xml
deleted file mode 100644
index d3cae18..0000000
--- a/v7/mediarouter/res/values-sq/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">"Sistemi"</string>
-    <string name="mr_user_route_category_name" msgid="7498112907524977311">"Pajisjet"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Butoni i transmetimit"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Butoni i transmetimit. Je i shkëputur"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Butoni i transmetimit. Po lidhet"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Butoni i transmetimit. Je i lidhur"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Transmeto te"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Po kërkon pajisje"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Shkëpute"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Ndalo transmetimin"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Mbyll"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Luaj"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"Pauzë"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Ndalo"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Zgjeroje"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Palose"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Kopertina e albumit"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Rrëshqitësi i volumit"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nuk u zgjodh asnjë media"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nuk jepet asnjë informacion"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Po transmeton ekranin"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-sr/strings.xml b/v7/mediarouter/res/values-sr/strings.xml
deleted file mode 100644
index ac53dff..0000000
--- a/v7/mediarouter/res/values-sr/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-sv/strings.xml b/v7/mediarouter/res/values-sv/strings.xml
deleted file mode 100644
index 73f26ae..0000000
--- a/v7/mediarouter/res/values-sv/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">"Enheter"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Cast-knappen"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Cast-knappen. Frånkopplad"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Cast-knappen. Ansluter"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Cast-knappen. Ansluten"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Casta till"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Letar efter enheter"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Koppla från"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Sluta casta"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Stäng"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Spela upp"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"Pausa"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Avbryt"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Utöka"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Komprimera"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Skivomslag"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Volymreglage"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Inga media har valts"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Det finns ingen information"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Skärmen castas"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-sw/strings.xml b/v7/mediarouter/res/values-sw/strings.xml
deleted file mode 100644
index 0138fa4..0000000
--- a/v7/mediarouter/res/values-sw/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">"Mfumo"</string>
-    <string name="mr_user_route_category_name" msgid="7498112907524977311">"Vifaa"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Kitufe cha kutuma"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Kitufe cha kutuma. Kimeondolewa"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Kitufe cha kutuma. Kinaunganisha"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Kitufe cha kutuma. Kimeunganishwa"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Tuma kwenye"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Inatafuta vifaa"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Ondoa"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Acha kutuma"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Funga"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Cheza"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"Sitisha"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Simamisha"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Panua"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Kunja"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Sanaa ya albamu"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Kitelezi cha sauti"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Hakuna maudhui yaliyochaguliwa"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Hakuna maelezo yaliyopatikana"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Inatuma skrini"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-ta/strings.xml b/v7/mediarouter/res/values-ta/strings.xml
deleted file mode 100644
index 9888472..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-te/strings.xml b/v7/mediarouter/res/values-te/strings.xml
deleted file mode 100644
index c36a58d..0000000
--- a/v7/mediarouter/res/values-te/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-th/strings.xml b/v7/mediarouter/res/values-th/strings.xml
deleted file mode 100644
index d9be678..0000000
--- a/v7/mediarouter/res/values-th/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-tl/strings.xml b/v7/mediarouter/res/values-tl/strings.xml
deleted file mode 100644
index 4b4922b..0000000
--- a/v7/mediarouter/res/values-tl/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">"Mga Device"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Button na I-cast"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Button na I-cast. Nadiskonekta"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Button na I-cast. Kumokonekta"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Button na I-cast. Nakakonekta"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"I-cast sa"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Naghahanap ng mga device"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Idiskonekta"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Ihinto ang pag-cast"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Isara"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"I-play"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"I-pause"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Ihinto"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Palawakin"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"I-collapse"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Album art"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Slider ng volume"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Walang piniling media"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Walang available na impormasyon"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Kina-cast ang screen"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-tr/strings.xml b/v7/mediarouter/res/values-tr/strings.xml
deleted file mode 100644
index 8189092..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ı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/res/values-uk/strings.xml
deleted file mode 100644
index 136d449..0000000
--- a/v7/mediarouter/res/values-uk/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-ur/strings.xml b/v7/mediarouter/res/values-ur/strings.xml
deleted file mode 100644
index c3f08ce..0000000
--- a/v7/mediarouter/res/values-ur/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-uz/strings.xml b/v7/mediarouter/res/values-uz/strings.xml
deleted file mode 100644
index 2f9a8a2..0000000
--- a/v7/mediarouter/res/values-uz/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">"Tizim"</string>
-    <string name="mr_user_route_category_name" msgid="7498112907524977311">"Qurilmalar"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Translatsiya tugmasi"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Translatsiya tugmasi. Uzildi"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Translatsiya tugmasi. Ulanmoqda"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Translatsiya tugmasi. Ulandi"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Quyidagiga translatsiya qilish:"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Qurilmalarni topish"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Ulanishni uzish"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Translatsiyani to‘xtatish"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Yopish"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Boshlash"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"To‘xtatib turish"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"To‘xtatish"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Yoyish"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Yig‘ish"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Albom muqovasi"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Tovush balandligi slayderi"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Multimedia tanlamagan"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Hech qanday ma’lumot yo‘q"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Ekranni translatsiya qilish"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-vi/strings.xml b/v7/mediarouter/res/values-vi/strings.xml
deleted file mode 100644
index 3fbc252..0000000
--- a/v7/mediarouter/res/values-vi/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">"Hệ thống"</string>
-    <string name="mr_user_route_category_name" msgid="7498112907524977311">"Thiết bị"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Nút truyền"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Nút truyền. Đã ngắt kết nối"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Nút truyền. Đang kết nối"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Nút truyền. Đã kết nối"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Truyền tới"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Đang tìm thiết bị"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Ngắt kết nối"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Dừng truyền"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Đóng"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Phát"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"Tạm dừng"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Dừng"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Mở rộng"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Thu gọn"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Ảnh bìa album"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Thanh trượt âm lượng"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Không có phương tiện nào được chọn"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Không có thông tin nào"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Đang truyền màn hình"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-zh-rCN/strings.xml b/v7/mediarouter/res/values-zh-rCN/strings.xml
deleted file mode 100644
index be2ee12..0000000
--- a/v7/mediarouter/res/values-zh-rCN/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-zh-rHK/strings.xml b/v7/mediarouter/res/values-zh-rHK/strings.xml
deleted file mode 100644
index 26a4824..0000000
--- a/v7/mediarouter/res/values-zh-rHK/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-zh-rTW/strings.xml b/v7/mediarouter/res/values-zh-rTW/strings.xml
deleted file mode 100644
index b5f6942..0000000
--- a/v7/mediarouter/res/values-zh-rTW/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-zu/strings.xml b/v7/mediarouter/res/values-zu/strings.xml
deleted file mode 100644
index 9ffb583..0000000
--- a/v7/mediarouter/res/values-zu/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">"Isistimu"</string>
-    <string name="mr_user_route_category_name" msgid="7498112907524977311">"Amadivayisi"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Inkinobho ye-Cast"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Inkinobho yokusakaza. Kunqanyuliwe"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Inkinobho yokusakaza. Kuyaxhunywa"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Inkinobho yokusakaza. Kuxhunyiwe"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Sakaza ku-"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Ithola amadivayisi"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Nqamula"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Misa ukusakaza"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Vala"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Dlala"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"Misa isikhashana"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Misa"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Nweba"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Goqa"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Ubuciko be-albhamu"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Isilayida sevolumu"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Ayikho imidiya ekhethiwe"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Alukho ulwazi olutholakalayo"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Isikrini sokusakaza"</string>
-</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/AndroidManifest.xml b/v7/mediarouter/src/main/AndroidManifest.xml
similarity index 100%
rename from v7/mediarouter/AndroidManifest.xml
rename to v7/mediarouter/src/main/AndroidManifest.xml
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/src/main/res/values-af/strings.xml b/v7/mediarouter/src/main/res/values-af/strings.xml
new file mode 100644
index 0000000..1968699
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-af/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="6445173646164603280">"Stelsel"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Toestelle"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Uitsaai-knoppie"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Uitsaai-knoppie. Ontkoppel"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Uitsaai-knoppie. Koppel tans"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Uitsaai-knoppie. Gekoppel"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Saai uit na"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Soek tans toestelle"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Ontkoppel"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Hou op uitsaai"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Maak toe"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Speel"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Onderbreek"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Stop"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Vou uit"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Vou in"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Albumkunswerk"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Volumeglyer"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Geen media is gekies nie"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Geen inligting is beskikbaar nie"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Saai tans skerm uit"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-am/strings.xml b/v7/mediarouter/src/main/res/values-am/strings.xml
new file mode 100644
index 0000000..5e4eb42
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-am/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="6445173646164603280">"ሥርዓት"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"መሣሪያዎች"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"የCast አዝራር"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Cast አዝራር። ግንኙነት ተቋርጧል"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Cast አዝራር። በመገናኘት ላይ"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"የCast አዝራር። ተገናኝቷል"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Cast አድርግ ወደ"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"መሣሪያዎችን በማግኘት ላይ"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"ግንኙነት አቋርጥ"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Cast ማድረግ አቁም"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"ዝጋ"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"አጫውት"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"ለአፍታ አቁም"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"አቁም"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"ዘርጋ"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"ሰብስብ"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"የአልበም ስነ-ጥበብ"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"ተንሸራታች የድምፅ መቆጣጠሪያ"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"ምንም ማህደረ መረጃ አልተመረጠም"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"ምንም መረጃ አይገኝም"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"ማያ ገጽን Cast በማድረግ ላይ"</string>
+</resources>
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..12a6df3
--- /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="6445173646164603280">"النظام"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"الأجهزة"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"زر الإرسال"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"زر الإرسال. تم قطع الاتصال"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"زر الإرسال. جارٍ الاتصال"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"زر الإرسال. تم الاتصال"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"إرسال إلى"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"جارٍ البحث عن أجهزة"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"قطع الاتصال"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"إيقاف الإرسال"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"إغلاق"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"تشغيل"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"إيقاف مؤقت"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"إيقاف"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"توسيع"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"تصغير"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"صورة الألبوم"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"شريط تمرير مستوى الصوت"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"لم يتم اختيار أي وسائط"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"لا تتوفر أي معلومات"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"جارٍ إرسال الشاشة"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-az/strings.xml b/v7/mediarouter/src/main/res/values-az/strings.xml
new file mode 100644
index 0000000..651c84c
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-az/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="6445173646164603280">"Sistem"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Cihazlar"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Yayım düyməsi"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Yayım düyməsi. Bağlantı kəsildi"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Yayım düyməsi. Qoşulur"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Yayım düyməsi. Qoşuldu"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Bura yayımlayın"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Cihazlar axtarılır"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Ayırın"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Yayımı dayandırın"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Bağlayın"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Fasilə verin"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Dayandırın"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Dayandırın"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Genişləndirin"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Yığcamlaşdırın"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Albom incəsənəti"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Səs ayarlayıcısı"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Media seçilməyib"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Əlçatan məlumat yoxdur"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Ekran yayımlanır"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-b+sr+Latn/strings.xml b/v7/mediarouter/src/main/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..805709b
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-b+sr+Latn/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="6445173646164603280">"Sistem"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Uređaji"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Dugme Prebaci"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Dugme Prebaci. Veza je prekinuta"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Dugme Prebaci. Povezuje se"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Dugme Prebaci. Povezan je"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Prebacite na"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Traže se uređaji"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Prekini vezu"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Zaustavi prebacivanje"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Zatvori"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Pusti"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Pauziraj"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Zaustavi"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Proširi"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Skupi"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Omot albuma"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Klizač za jačinu zvuka"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Nema izabranih medija"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Nema dostupnih informacija"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Prebacuje se ekran"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-be/strings.xml b/v7/mediarouter/src/main/res/values-be/strings.xml
new file mode 100644
index 0000000..b0ae4d5
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-be/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="6445173646164603280">"Сістэма"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Прылады"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Кнопка трансляцыі"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Кнопка трансляцыі. Прылада адключана"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Кнопка трансляцыі. Прылада падключаецца"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Кнопка трансляцыі. Прылада падключана"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Трансліраваць на прыладу"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Пошук прылад"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Адключыць"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Спыніць трансляцыю"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Закрыць"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Прайграць"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Паўза"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Спыніць"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Разгарнуць"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Згарнуць"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Вокладка альбома"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Рэгулятар гучнасці"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Медыяфайл не выбраны"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Інфармацыя адсутнічае"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Экран трансліруецца"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-bg/strings.xml b/v7/mediarouter/src/main/res/values-bg/strings.xml
new file mode 100644
index 0000000..7491533
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-bg/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="6445173646164603280">"Система"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Устройства"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Бутон за предаване"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Бутон за предаване. Връзката е прекратена"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Бутон за предаване. Установява се връзка"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Бутон за предаване. Установена е връзка"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Предаване към"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Търсят се устройства"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Прекратяване на връзката"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Спиране на предаването"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Затваряне"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Възпроизвеждане"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Поставяне на пауза"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Спиране"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Разгъване"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Свиване"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Обложка на албума"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Плъзгач за силата на звука"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Няма избрана мултимедия"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Няма налична информация"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Екранът се предава"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-bn/strings.xml b/v7/mediarouter/src/main/res/values-bn/strings.xml
new file mode 100644
index 0000000..b3ed757
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-bn/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="6445173646164603280">"সিস্টেম"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"ডিভাইস"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"কাস্ট করার বোতাম"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"কাস্ট করার বোতাম। কানেক্ট করা নেই"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"কাস্ট করার বোতাম। কানেক্ট করা হচ্ছে"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"কাস্ট করার বোতাম। কানেক্ট হয়েছে"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"এখানে কাস্ট করুন"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"ডিভাইস খোঁজা হচ্ছে"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"ডিসকানেক্ট"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"কাস্ট করা বন্ধ করুন"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"বন্ধ করুন"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"চালান"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"পজ করুন"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"থামান"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"বড় করে দেখুন"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"আড়াল করুন"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"অ্যালবাম আর্ট"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"ভলিউম স্লাইডার"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"কোনও মিডিয়া বেছে নেওয়া হয়নি"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"কোনও তথ্য উপলভ্য নেই"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"স্ক্রিন কাস্ট করা হচ্ছে"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-bs/strings.xml b/v7/mediarouter/src/main/res/values-bs/strings.xml
new file mode 100644
index 0000000..553efdf
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-bs/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="6445173646164603280">"Sistem"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Uređaji"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Dugme za emitiranje"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Dugme za emitiranje. Veza je prekinuta"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Dugme za emitiranje. Povezivanje"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Dugme za emitiranje. Povezano"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Emitiranje na"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Traženje uređaja"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Prekini vezu"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Zaustavi emitiranje"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Zatvori"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Reproduciraj"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Pauza"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Zaustavi"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Proširi"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Skupi"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Omot albuma"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Klizač za jačinu zvuka"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Nije odabran nijedan medij"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Nema dostupnih informacija"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Emitiranje ekrana"</string>
+</resources>
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..e6a2f71
--- /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="6445173646164603280">"Sistema"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Dispositius"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Botó d\'emetre"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Botó d\'emetre. Desconnectat."</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Botó d\'emetre. S\'està connectant."</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Botó d\'emetre. Connectat."</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Emet contingut a"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"S\'estan cercant dispositius"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Desconnecta"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Atura l\'emissió"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Tanca"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Reprodueix"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Posa en pausa"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Atura"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Desplega"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Replega"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Imatge de l\'àlbum"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Control lliscant de volum"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"No hi ha contingut multimèdia seleccionat"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"No hi ha informació disponible"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"S\'està emetent la pantalla"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-cs/strings.xml b/v7/mediarouter/src/main/res/values-cs/strings.xml
new file mode 100644
index 0000000..a914d34
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-cs/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="6445173646164603280">"Systém"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Zařízení"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Tlačítko odesílání"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Tlačítko odesílání. Odpojeno"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Tlačítko odesílání. Připojování"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Tlačítko odesílání. Připojeno"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Odeslat do zařízení"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Hledání zařízení"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Odpojit"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Zastavit odesílání"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Zavřít"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Přehrát"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Pozastavit"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Ukončit"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Rozbalit"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Sbalit"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Obal alba"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Posuvník hlasitosti"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Není vybrán žádný mediální obsah"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Nejsou k dispozici žádné informace"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Odesílání obsahu obrazovky"</string>
+</resources>
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..5736cb5
--- /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="6445173646164603280">"System"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Enheder"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Cast-knap"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Cast-knap. Forbindelsen er afbrudt"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Cast-knap. Opretter forbindelse"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Cast-knap. Tilsluttet"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Cast til"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Finder enheder"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Afbryd"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Stop med at caste"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Luk"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Afspil"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Sæt på pause"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Stop"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Udvid"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Skjul"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Albumgrafik"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Lydstyrkeskyder"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Ingen medier er markeret"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Der er ingen tilgængelige oplysninger"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Skærmen castes"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-de/strings.xml b/v7/mediarouter/src/main/res/values-de/strings.xml
new file mode 100644
index 0000000..bfab0be
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-de/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="6445173646164603280">"System"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Geräte"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Cast-Symbol"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Cast-Symbol. Nicht verbunden"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Cast-Symbol. Verbindung wird hergestellt"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Cast-Symbol. Verbunden"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Streamen auf"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Keine Geräte gefunden"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Trennen"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Streaming beenden"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Schließen"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Wiedergeben"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Pausieren"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Beenden"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Maximieren"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Minimieren"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Albumcover"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Schieberegler für die Lautstärke"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Keine Medien ausgewählt"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Keine Informationen verfügbar"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Bildschirm wird übertragen"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-el/strings.xml b/v7/mediarouter/src/main/res/values-el/strings.xml
new file mode 100644
index 0000000..6290c3d
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-el/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="6445173646164603280">"Σύστημα"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Συσκευές"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Κουμπί μετάδοσης"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Κουμπί μετάδοσης. Αποσυνδέθηκε."</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Κουμπί μετάδοση. Σύνδεση."</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Κουμπί μετάδοσης. Συνδέθηκε."</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Μετάδοση σε"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Εύρεση συσκευών"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Αποσύνδεση"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Διακοπή μετάδοσης"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Κλείσιμο"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Αναπαραγωγή"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Παύση"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Διακοπή"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Ανάπτυξη"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Σύμπτυξη"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Εξώφυλλο άλμπουμ"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Ρυθμιστικό έντασης ήχου"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Δεν επιλέχθηκαν μέσα"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Δεν υπάρχουν διαθέσιμες πληροφορίες"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Μετάδοση οθόνης"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-en-rAU/strings.xml b/v7/mediarouter/src/main/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000..420d536
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-en-rAU/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="6445173646164603280">"System"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Devices"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Cast button"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Cast button. Disconnected"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Cast button. Connecting"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Cast button. Connected"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Cast to"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Finding devices"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Disconnect"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Stop casting"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Close"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Play"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Pause"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Stop"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Expand"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Collapse"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Album art"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Volume slider"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"No media selected"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"No info available"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Casting screen"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-en-rCA/strings.xml b/v7/mediarouter/src/main/res/values-en-rCA/strings.xml
new file mode 100644
index 0000000..420d536
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-en-rCA/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="6445173646164603280">"System"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Devices"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Cast button"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Cast button. Disconnected"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Cast button. Connecting"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Cast button. Connected"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Cast to"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Finding devices"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Disconnect"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Stop casting"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Close"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Play"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Pause"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Stop"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Expand"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Collapse"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Album art"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Volume slider"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"No media selected"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"No info available"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Casting screen"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-en-rGB/strings.xml b/v7/mediarouter/src/main/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..420d536
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-en-rGB/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="6445173646164603280">"System"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Devices"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Cast button"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Cast button. Disconnected"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Cast button. Connecting"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Cast button. Connected"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Cast to"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Finding devices"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Disconnect"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Stop casting"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Close"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Play"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Pause"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Stop"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Expand"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Collapse"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Album art"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Volume slider"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"No media selected"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"No info available"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Casting screen"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-en-rIN/strings.xml b/v7/mediarouter/src/main/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..420d536
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-en-rIN/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="6445173646164603280">"System"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Devices"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Cast button"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Cast button. Disconnected"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Cast button. Connecting"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Cast button. Connected"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Cast to"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Finding devices"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Disconnect"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Stop casting"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Close"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Play"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Pause"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Stop"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Expand"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Collapse"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Album art"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Volume slider"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"No media selected"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"No info available"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Casting screen"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-en-rXC/strings.xml b/v7/mediarouter/src/main/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000..03083ad
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-en-rXC/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="6445173646164603280">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‏‏‏‎‎‎‏‏‏‎‏‏‎‏‏‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‎‏‎‏‏‎‎‏‏‎‏‏‎‎‎‏‏‎‎‏‎‎‎‎‎System‎‏‎‎‏‎"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‎‏‎‎‏‏‏‎‎‎‏‎‎‎‏‏‎‏‎‎‏‏‎‏‎‏‏‏‎‎‏‏‎‎‎‎‎‏‎‎‏‎‏‏‏‎‎‏‎‏‎Devices‎‏‎‎‏‎"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‎‏‎‏‏‏‎‎‎‏‎‎‏‎‎‎‏‏‎‏‏‎‎‏‎‏‎‎‎‏‏‎‏‎‏‎‏‏‎‎‎‎‏‏‎‎‎‏‏‎‏‎‏‏‏‎Cast button‎‏‎‎‏‎"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‏‏‎‏‏‎‏‎‎‏‏‎‎‏‏‏‎‎‎‏‏‏‏‏‎‏‎‏‏‎‎‎‏‎‏‎‏‏‏‎‎‎‏‎‏‎‎‎‎‏‎‏‎‏‏‎‎Cast button. Disconnected‎‏‎‎‏‎"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‎‎‏‎‏‎‎‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‎‏‏‏‏‏‏‎‎‏‎‎‎‏‎‏‎‏‏‏‏‎‏‏‏‎‎‎‎‏‎‎Cast button. Connecting‎‏‎‎‏‎"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‎‎‎‎‎‎‏‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‏‏‎‏‎‏‎‏‏‎‏‎‏‎‎‎‎‎‏‎‏‎‎‎‎‎‏‏‎‎‏‏‎Cast button. Connected‎‏‎‎‏‎"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‎‎‏‏‎‎‏‎‏‏‏‎‏‏‎‎‎‏‏‎‎‏‏‎‏‏‏‎‏‎‎‏‏‎‎‎‏‏‏‏‎‎‏‎‎‎‎‏‏‎‎‎‏‎‎‏‏‎Cast to‎‏‎‎‏‎"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‏‎‏‎‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‏‏‎‎‏‎‏‎‏‎‏‏‎‎‎‎‎‏‏‎‎‏‎‏‏‏‎‏‏‎‏‏‎‎Finding devices‎‏‎‎‏‎"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‏‏‏‏‏‏‏‎‏‎‎‎‎‏‏‎‎‎‏‏‎‏‏‎‎‎‏‎‏‏‏‎‎‏‎‏‎‎‎‏‎‏‏‎‏‎‏‎‎‏‏‎‎‎‎‎‎Disconnect‎‏‎‎‏‎"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‏‎‏‏‏‎‏‎‏‏‏‎‎‎‏‎‏‎‎‏‎‎‎‏‏‏‏‎‎‎‎‎‏‎‏‏‎‏‎‎‎‎‎‏‏‎‎‏‎‎‏‎‎‎‎‎Stop casting‎‏‎‎‏‎"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‏‎‏‏‏‏‏‎‎‏‎‎‎‏‏‎‎‏‏‎‎‎‏‎‏‏‏‏‏‎‏‎‏‎‎‎‎‏‏‎‏‏‎‎‏‎‏‎‎‎‏‏‎‎‏‎‎‎Close‎‏‎‎‏‎"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‏‏‏‏‏‏‎‏‏‏‎‎‎‏‏‎‏‎‏‎‎‎‏‏‏‎‎‎‎‎‎‎‎‏‏‎‎‎‏‎‎‎‎‏‏‎‎‏‎‎‏‎‎‎‎‎‎Play‎‏‎‎‏‎"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‏‎‏‎‏‏‏‏‏‏‎‎‏‎‏‏‏‎‎‏‎‎‎‏‎‎‏‎‏‎‏‎‏‎‏‎‏‎‎‏‏‎‏‏‏‏‎‎‏‏‏‏‏‎‏‎Pause‎‏‎‎‏‎"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‏‏‏‏‎‎‎‎‏‏‎‏‏‏‏‏‏‎‏‎‎‏‎‏‏‎‎‏‎‏‎‏‏‎‎‏‏‎‏‏‏‏‎‎‏‏‏‏‎‎‏‎‏‏‎Stop‎‏‎‎‏‎"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‎‎‏‎‎‎‎‎‏‎‏‏‏‏‏‎‎‎‏‎‏‏‎‏‏‏‏‎‏‎‎‎‏‎‏‎‏‎‏‎‎‎‏‏‎‏‏‏‏‏‎‎‏‏‏‎Expand‎‏‎‎‏‎"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‎‎‎‎‎‏‎‏‎‏‏‏‏‏‎‎‏‏‎‏‎‏‎‎‏‎‏‏‏‎‏‏‎‎‏‏‏‎‎‎‎‏‎‏‏‎‎‎‎‏‎‎‎‏‏‎Collapse‎‏‎‎‏‎"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‏‏‏‏‎‏‎‎‎‏‏‎‎‏‏‎‎‏‎‏‏‎‏‎‏‎‎‏‏‏‎‏‎‎‎‏‏‏‎‎‎‎‏‎‏‎‏‏‏‎‎‎‎‎Album art‎‏‎‎‏‎"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‏‎‏‏‎‏‎‏‎‏‎‏‏‏‎‏‎‎‎‎‏‏‏‏‎‎‏‎‎‎‏‎‎‎‏‏‎‎‏‎‎‏‏‏‏‎‏‏‎‎‏‎‎‏‎‏‏‎Volume slider‎‏‎‎‏‎"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‏‎‎‎‏‏‎‎‏‏‎‏‎‏‏‎‏‎‏‏‎‎‎‏‎‎‏‏‏‏‏‏‎‏‎‎‎‏‎‎‎‎‏‎‎‏‎‎‎‏‎‏‎‏‏‎No media selected‎‏‎‎‏‎"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‏‎‎‎‏‎‎‏‏‏‎‎‎‏‏‎‎‎‏‏‎‏‏‎‏‏‎‏‏‏‏‏‏‎‏‎‎‏‏‏‎‎‏‏‏‎‏‏‏‏‎‏‎‏‏‎‎‎No info available‎‏‎‎‏‎"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‎‏‏‎‎‏‏‎‏‏‏‏‎‎‎‏‎‏‎‎‎‎‏‏‎‎‎‎‏‏‏‏‎‏‏‏‎‏‎‎‏‏‎‏‏‏‏‎‏‏‏‏‏‏‎‎‎Casting screen‎‏‎‎‏‎"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-es-rUS/strings.xml b/v7/mediarouter/src/main/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..51a2955
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-es-rUS/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="6445173646164603280">"Sistema"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Dispositivos"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Botón para transmitir"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Botón para transmitir (desconectado)"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Botón para transmitir (conectando)"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Botón para transmitir (conectado)"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Transmitir a"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Buscando dispositivos"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Desconectar"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Detener transmisión"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Cerrar"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Reproducir"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Pausar"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Detener"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Expandir"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Contraer"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Imagen del álbum"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Control deslizante del volumen"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"No se seleccionó ningún contenido multimedia"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Sin información disponible"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Transmitiendo pantalla"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-es/strings.xml b/v7/mediarouter/src/main/res/values-es/strings.xml
new file mode 100644
index 0000000..e07a751
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-es/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="6445173646164603280">"Sistema"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Dispositivos"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Botón de enviar"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Botón de enviar. Desconectado"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Botón de enviar. Conectando"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Botón de enviar. Conectado"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Enviar a"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Buscando dispositivos"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Desconectar"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Detener envío"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Cerrar"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Reproducir"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Pausar"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Detener"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Mostrar"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Ocultar"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Carátula del álbum"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Control deslizante de volumen"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"No se ha seleccionado contenido multimedia"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"No hay información disponible"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Enviando pantalla"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-et/strings.xml b/v7/mediarouter/src/main/res/values-et/strings.xml
new file mode 100644
index 0000000..4ff3f62
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-et/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="6445173646164603280">"Süsteem"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Seadmed"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Ülekandenupp"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Ülekandenupp. Ühendus on katkestatud"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Ülekandenupp. Ühendamine"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Ülekandenupp. Ühendatud"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Ülekandmine seadmesse"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Seadmete otsimine"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Katkesta ühendus"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Peata ülekandmine"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Sulgemine"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Esitamine"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Peatamine"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Peatamine"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Laiendamine"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Ahendamine"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Albumi kujundus"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Helitugevuse liugur"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Meediat pole valitud"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Teave pole saadaval"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Ekraanikuva ülekandmine"</string>
+</resources>
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..18aeed3
--- /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="6445173646164603280">"Sistema"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Gailuak"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Igorri botoia"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Igortzeko botoia. Deskonektatuta"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Igortzeko botoia. Konektatzen"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Igortzeko botoia. Konektatuta"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Igorri hona"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Gailuak bilatzen"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Deskonektatu"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Utzi igortzeari"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Itxi"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Erreproduzitu"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Pausatu"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Gelditu"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Zabaldu"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Tolestu"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Albumaren azala"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Bolumenaren graduatzailea"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Ez da ezer hautatu"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Ez dago informaziorik"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Pantaila igortzen"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-fa/strings.xml b/v7/mediarouter/src/main/res/values-fa/strings.xml
new file mode 100644
index 0000000..eb0ea6c
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-fa/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="6445173646164603280">"سیستم"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"دستگاه‌ها"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"دکمه ارسال محتوا"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"دکمه فرستادن. اتصال قطع شد"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"دکمه فرستادن. درحال اتصال"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"دکمه فرستادن. متصل"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"ارسال محتوا به"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"پیدا کردن دستگاه‌ها"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"قطع اتصال"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"توقف ارسال محتوا"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"بستن"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"پخش"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"مکث"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"توقف"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"بزرگ کردن"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"کوچک کردن"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"عکس روی جلد آلبوم"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"لغزنده میزان صدا"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"رسانه‌ای انتخاب نشده است"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"اطلاعات دردسترس نیست"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"صفحه ارسال محتوا"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-fi/strings.xml b/v7/mediarouter/src/main/res/values-fi/strings.xml
new file mode 100644
index 0000000..a365147
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-fi/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="6445173646164603280">"Järjestelmä"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Laitteet"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Cast-painike"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Cast-painike. Yhteys katkaistu"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Cast-painike. Yhdistetään"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Cast-painike. Yhdistetty"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Suoratoiston kohde"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Etsitään laitteita"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Katkaise yhteys"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Lopeta suoratoisto"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Sulje"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Toista"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Keskeytä"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Lopeta"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Laajenna"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Tiivistä"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Albumin kansikuva"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Äänenvoimakkuuden liukusäädin"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Ei valittua mediaa"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Ei tietoja saatavilla"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Suoratoistetaan näyttöä"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-fr-rCA/strings.xml b/v7/mediarouter/src/main/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..8df9031
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-fr-rCA/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="6445173646164603280">"Système"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Appareils"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Bouton Diffuser"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Bouton Diffuser. Déconnecté"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Bouton Diffuser. Connexion en cours…"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Bouton Diffuser. Connecté"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Diffuser vers"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Recherche d\'appareils"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Dissocier"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Arrêter la diffusion"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Fermer"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Lire"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Pause"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Arrêter"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Développer"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Réduire"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Image de l\'album"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Curseur de réglage du volume"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Aucun média sélectionné"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Aucune donnée trouvée"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Diffusion de l\'écran en cours"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-fr/strings.xml b/v7/mediarouter/src/main/res/values-fr/strings.xml
new file mode 100644
index 0000000..cfce49b
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-fr/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="6445173646164603280">"Système"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Appareils"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Icône Cast"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Icône Cast. Déconnecté"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Icône Cast. Connexion…"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Icône Cast. Connecté"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Caster sur"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Recherche d\'appareils…"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Déconnecter"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Arrêter la diffusion"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Fermer"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Lecture"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Pause"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Arrêt"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Développer"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Réduire"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Image de l\'album"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Curseur de volume"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Aucun contenu multimédia sélectionné"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Aucune information disponible"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Diffusion de l\'écran"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-gl/strings.xml b/v7/mediarouter/src/main/res/values-gl/strings.xml
new file mode 100644
index 0000000..2eb5e04
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-gl/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="6445173646164603280">"Sistema"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Dispositivos"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Botón de emitir"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Botón de emitir. Desconectado"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Botón de emitir. Conectando"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Botón de emitir. Conectado"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Emitir en"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Buscando dispositivos"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Desconectar"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Deter emisión"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Pechar"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Reproducir"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Pausar"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Deter"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Despregar"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Contraer"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Portada do álbum"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Control desprazable do volume"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Non se seleccionou ningún recurso multimedia"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Non hai información dispoñible"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Emitindo a pantalla"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-gu/strings.xml b/v7/mediarouter/src/main/res/values-gu/strings.xml
new file mode 100644
index 0000000..8459bcd
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-gu/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="6445173646164603280">"સિસ્ટમ"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"ઉપકરણો"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"કાસ્ટ બટન"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"કાસ્ટ બટન. ડિસ્કનેક્ટેડ"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"કાસ્ટ બટન. કનેક્ટ કરી રહ્યાં છીએ"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"કાસ્ટ બટન. કનેક્ટેડ"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"આના પર કાસ્ટ કરો"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"ઉપકરણો શોધી રહ્યાં છીએ"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"ડિસ્કનેક્ટ કરો"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"કાસ્ટ કરવાનું રોકો"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"બંધ કરો"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"ચલાવો"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"થોભાવો"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"રોકો"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"વિસ્તાર કરો"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"સંકુચિત કરો"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"આલ્બમ આર્ટ"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"વૉલ્યુમ સ્લાઇડર"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"કોઈ મીડિયા પસંદ કરેલ નથી"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"કોઈ માહિતી ઉપલબ્ધ નથી"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"સ્ક્રીનને કાસ્ટ કરી રહ્યાં છીએ"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-hi/strings.xml b/v7/mediarouter/src/main/res/values-hi/strings.xml
new file mode 100644
index 0000000..891d765
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-hi/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="6445173646164603280">"सिस्‍टम"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"डिवाइस"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"कास्ट करें बटन"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"कास्ट करें बटन. नहीं जुड़ा है"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"कास्ट करें बटन. जुड़ रहा है"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"कास्ट करें बटन. जुड़ा है"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"इस पर कास्‍ट करें"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"डिवाइस ढूंढे जा रहे हैं"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"कनेक्शन हटाएं"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"कास्ट करना रोकें"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"बंद करें"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"चलाएं"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"रोकें"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"रुकें"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"सदस्याें की सूची को बड़ा करके देखें"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"सदस्याें की सूची छोटी करें"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"एल्बम आर्ट"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"आवाज़ बढ़ाने या घटाने वाला स्लाइडर"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"कोई मीडिया चुना नहीं गया"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"कोई जानकारी मौजूद नहीं है"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"स्क्रीन कास्ट की जा रही है"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-hr/strings.xml b/v7/mediarouter/src/main/res/values-hr/strings.xml
new file mode 100644
index 0000000..e17a0e7
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-hr/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="6445173646164603280">"Sustav"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Uređaji"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Gumb za emitiranje"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Gumb za emitiranje. Veza prekinuta"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Gumb za emitiranje. Povezivanje"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Gumb za emitiranje. Povezan"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Emitiranje na"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Traženje uređaja"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Prekini"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Zaustavi emitiranje"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Zatvori"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Pokreni"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Pauza"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Zaustavi"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Proširi"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Sažmi"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Naslovnica albuma"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Klizač za glasnoću"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Nije odabran nijedan medij"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Informacije nisu dostupne"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Emitiranje zaslona"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-hu/strings.xml b/v7/mediarouter/src/main/res/values-hu/strings.xml
new file mode 100644
index 0000000..a9f80f4
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-hu/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="6445173646164603280">"Rendszer"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Eszközök"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Átküldés gomb"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Átküldés gomb. Kapcsolat bontva"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Átküldés gomb. Csatlakozás"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Átküldés gomb. Csatlakoztatva"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Átküldés ide:"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Eszközök keresése"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Leválasztás"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Átküldés leállítása"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Bezárás"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Lejátszás"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Szünet"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Leállítás"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Kibontás"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Összecsukás"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Lemezborító"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Hangerőszabályzó"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Nincs médiatartalom kiválasztva"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Nincs információ"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Képernyőtartalom átküldése…"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-hy/strings.xml b/v7/mediarouter/src/main/res/values-hy/strings.xml
new file mode 100644
index 0000000..e48fac5
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-hy/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="6445173646164603280">"Համակարգ"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Սարքեր"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Հեռարձակման կոճակ"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Հեռարձակման կոճակ: Սարքն անջատած է:"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Հեռարձակման կոճակ: Սարքը միանում է:"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Հեռարձակման կոճակ: Սարքը միացված է:"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Ընտրեք սարք"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Սարքերի որոնում"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Անջատել"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Դադարեցնել հեռարձակումը"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Փակել"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Նվագարկել"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Ընդհատել"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Դադարեցնել"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Ընդարձակել"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Կոծկել"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Ալբոմի շապիկ"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Ձայնի ուժգնության կարգավորիչ"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Մեդիա ֆայլ չի ընտրվել"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Հասանելի տեղեկություններ չկան"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Էկրանի հեռարձակում"</string>
+</resources>
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..5a19254
--- /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="6445173646164603280">"Sistem"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Perangkat"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Tombol Cast"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Tombol Cast. Terputus"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Tombol Cast. Menghubungkan"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Tombol Cast. Terhubung"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Cast ke"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Mencari perangkat"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Putuskan hubungan"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Hentikan cast"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Tutup"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Putar"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Jeda"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Berhenti"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Luaskan"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Ciutkan"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Sampul album"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Penggeser volume"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Tidak ada media yang dipilih"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Tidak ada info yang tersedia"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Melakukan cast layar"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-is/strings.xml b/v7/mediarouter/src/main/res/values-is/strings.xml
new file mode 100644
index 0000000..bc3c36d
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-is/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="6445173646164603280">"Kerfi"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Tæki"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Útsendingarhnappur"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Útsendingarhnappur. Aftengt"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Útsendingarhnappur. Tengist"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Útsendingarhnappur. Tengt"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Senda út í"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Leitað að tækj"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Aftengja"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Stöðva útsendingu"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Loka"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Spila"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Hlé"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Stöðva"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Stækka"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Minnka"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Plötuumslag"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Hljóðstyrkssleði"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Ekkert efni valið"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Engar upplýsingar í boði"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Skjár sendur út"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-it/strings.xml b/v7/mediarouter/src/main/res/values-it/strings.xml
new file mode 100644
index 0000000..3bbfecd
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-it/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="6445173646164603280">"Sistema"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Dispositivi"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Pulsante Trasmetti"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Pulsante Trasmetti. Disconnesso"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Pulsante Trasmetti. Connessione in corso"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Pulsante Trasmetti. Connesso"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Trasmetti a"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Ricerca di dispositivi"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Disconnetti"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Interrompi trasmissione"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Chiudi"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Riproduci"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Metti in pausa"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Interrompi"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Espandi"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Comprimi"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Copertina"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Dispositivo di scorrimento del volume"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Nessun contenuto multimediale selezionato"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Nessuna informazione disponibile"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Trasmissione dello schermo"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-iw/strings.xml b/v7/mediarouter/src/main/res/values-iw/strings.xml
new file mode 100644
index 0000000..72ebc9c
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-iw/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="6445173646164603280">"מערכת"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"מכשירים"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"‏לחצן הפעלת Cast"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"‏לחצן הפעלת Cast. מנותק"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"‏לחצן הפעלת Cast. מתחבר"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"‏לחצן הפעלת Cast. מחובר"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"העברה אל"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"מחפש מכשירים"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"ניתוק"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"עצירת העברה"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"סגירה"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"הפעלה"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"השהיה"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"הפסקה"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"הרחבה"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"כיווץ"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"עטיפת אלבום"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"מחוון עוצמה"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"לא נבחרה מדיה"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"אין מידע זמין"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"העברת מסך מתבצעת"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-ja/strings.xml b/v7/mediarouter/src/main/res/values-ja/strings.xml
new file mode 100644
index 0000000..b33ffb9
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-ja/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="6445173646164603280">"システム"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"端末"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"キャスト アイコン"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"キャスト アイコン。接続解除済み"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"キャスト アイコン。接続中"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"キャスト アイコン。接続済み"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"キャスト先"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"端末を検索しています"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"接続を解除"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"キャストを停止"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"閉じる"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"再生"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"一時停止"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"停止"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"展開"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"折りたたむ"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"アルバムアート"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"音量スライダー"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"メディアを選択していません"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"情報がありません"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"画面をキャストしています"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-ka/strings.xml b/v7/mediarouter/src/main/res/values-ka/strings.xml
new file mode 100644
index 0000000..446a9e0
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-ka/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="6445173646164603280">"სისტემა"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"მოწყობილობები"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"ტრანსლირების ღილაკი"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"ტრანსლირების ღილაკი. გათიშული"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"ტრანსლირების ღილაკი. მიმდინარეობს დაკავშირება"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"ტრანსლირების ღილაკი. დაკავშირებული"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"ტრანსლირება:"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"მოწყობილობების მოძიება..."</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"გათიშვა"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"ტრანსლირების შეწყვეტა"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"დახურვა"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"დაკვრა"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"პაუზა"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"შეწყვეტა"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"გაშლა"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"ჩაკეცვა"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"ალბომის გარეკანი"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"ხმის სლაიდერი"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"მედია არჩეული არ არის"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"ინფორმაცია არ არის ხელმისაწვდომი"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"მიმდინარეობს ეკრანის ტრანსლირება"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-kk/strings.xml b/v7/mediarouter/src/main/res/values-kk/strings.xml
new file mode 100644
index 0000000..d512ff9
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-kk/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="6445173646164603280">"Жүйе"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Құрылғылар"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Трансляциялау түймесі"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Трансляциялау түймесі. Ажыратылды"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Трансляциялау түймесі. Қосылуда"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Трансляциялау түймесі. Қосылды"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Трансляция:"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Құрылғылар ізделуде"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Ажырату"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Трансляцияны тоқтату"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Жабу"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Ойнату"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Кідірту"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Тоқтату"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Жаю"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Жию"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Альбомның мұқабасы"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Дыбыс деңгейінің жүгірткісі"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Ешқандай медиафайл таңдалмаған"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Қолжетімді ақпарат жоқ"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Экранды трансляциялау"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-km/strings.xml b/v7/mediarouter/src/main/res/values-km/strings.xml
new file mode 100644
index 0000000..9303a1b
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-km/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="6445173646164603280">"ប្រព័ន្ធ"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"ឧបករណ៍"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"ប៊ូតុង​បញ្ជូន"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"ប៊ូតុង​បញ្ជូន។ បាន​ផ្តាច់"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"ប៊ូតុង​បញ្ជូន។ កំពុង​ភ្ជាប់"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"ប៊ូតុង​បញ្ជូន។ បាន​ភ្ជាប់​ហើយ"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"បញ្ជូន​ទៅ"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"កំពុង​ស្វែងរក​ឧបករណ៍"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"ផ្ដាច់"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"បញ្ឈប់​ការបញ្ជូន"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"បិទ"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"ចាក់"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"ផ្អាក"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"បញ្ឈប់"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"ពង្រីក"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"បង្រួម"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"រូបភាព​សិល្បៈ​ក្រប​អាល់ប៊ុម"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"របារកម្រិតសំឡេង"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"មិនបាន​ជ្រើសរើស​មេឌៀ​ទេ"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"មិនមានព័ត៌មានទេ"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"កំពុង​បញ្ជូន​អេក្រង់"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-kn/strings.xml b/v7/mediarouter/src/main/res/values-kn/strings.xml
new file mode 100644
index 0000000..f495017
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-kn/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="6445173646164603280">"ಸಿಸ್ಟಂ"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"ಸಾಧನಗಳು"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"ಬಿತ್ತರಿಸು ಬಟನ್‌"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"ಬಿತ್ತರಿಸು ಬಟನ್‌. ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸಲಾಗಿದೆ"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"ಬಿತ್ತರಿಸು ಬಟನ್‌. ಸಂಪರ್ಕಿಸಲಾಗುತ್ತಿದೆ"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"ಬಿತ್ತರಿಸು ಬಟನ್‌. ಸಂಪರ್ಕಿತಗೊಂಡಿದೆ"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"ಇದಕ್ಕೆ ಬಿತ್ತರಿಸಿ"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"ಸಾಧನಗಳನ್ನು ಹುಡುಕಲಾಗುತ್ತಿದೆ"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸಿ"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"ಬಿತ್ತರಿಸುವುದನ್ನು ನಿಲ್ಲಿಸಿ"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"ಮುಚ್ಚಿ"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"ಪ್ಲೇ"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"ವಿರಾಮ"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"ನಿಲ್ಲಿಸಿ"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"ಹಿಗ್ಗಿಸಿ"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"ಕುಗ್ಗಿಸಿ"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"ಆಲ್ಬಮ್ ಕಲೆ"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"ವಾಲ್ಯೂಮ್ ಸ್ಲೈಡರ್"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"ಯಾವುದೇ ಮಾಧ್ಯಮ ಆಯ್ಕೆ ಮಾಡಿಲ್ಲ"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"ಯಾವುದೇ ಮಾಹಿತಿ ಲಭ್ಯವಿಲ್ಲ"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"ಪರದೆಯನ್ನು ಬಿತ್ತರಿಸಲಾಗುತ್ತಿದೆ"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-ko/strings.xml b/v7/mediarouter/src/main/res/values-ko/strings.xml
new file mode 100644
index 0000000..178fab0
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-ko/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="6445173646164603280">"시스템"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"기기"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"전송 버튼"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"전송 버튼. 연결 해제됨"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"전송 버튼. 연결 중"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"전송 버튼. 연결됨"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"전송 대상"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"기기를 찾는 중"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"연결 끊기"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"전송 중지"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"닫기"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"재생"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"일시중지"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"중지"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"확대"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"접기"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"앨범아트"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"볼륨 슬라이더"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"선택된 미디어 없음"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"사용할 수 있는 정보 없음"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"화면 전송 중"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-ky/strings.xml b/v7/mediarouter/src/main/res/values-ky/strings.xml
new file mode 100644
index 0000000..100e5a5
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-ky/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="6445173646164603280">"Тутум"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Түзмөктөр"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Тышкы экранга чыгаруу баскычы"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Тышкы экранга чыгаруу баскычы. Түзмөк ажырап турат."</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Тышкы экранга чыгаруу баскычы. Түзмөк туташууда"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Тышкы экранга чыгаруу баскычы. Түзмөк туташып турат"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Түзмөккө чыгаруу"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Түзмөктөр изделүүдө"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Ажыратуу"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Тышкы экранга чыгарууну токтотуу"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Жабуу"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Угуу"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Тыным"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Токтотуу"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Жайып көрсөтүү"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Жыйыштыруу"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Альбом мукабасы"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Үндү катуулатуучу сыдырма"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Эч нерсе тандалган жок"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Эч маалымат жок"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Тышкы экранга чыгарылууда"</string>
+</resources>
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/src/main/res/values-lo/strings.xml b/v7/mediarouter/src/main/res/values-lo/strings.xml
new file mode 100644
index 0000000..79bd210
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-lo/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="6445173646164603280">"ລະບົບ"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"ອຸປະກອນ"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"ປຸ່ມສົ່ງສັນຍານ"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"ປຸ່ມສົ່ງສັນຍານ. ຕັດການເຊື່ອມຕໍ່ແລ້ວ"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"ປຸ່ມສົ່ງສັນຍານ. ກຳລັງເຊື່ອມຕໍ່"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"ປຸ່ມສົ່ງສັນຍານ. ເຊື່ອມຕໍ່ແລ້ວ"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"ສົ່ງສັນຍານໄປທີ່"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"ກຳລັງຊອກຫາອຸປະກອນ"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"ຕັດການເຊື່ອມຕໍ່"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"ຢຸດການສົ່ງສັນຍານ"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"ປິດ"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"ຫຼິ້ນ"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"ຢຸດຊົ່ວຄາວ"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"ຢຸດ"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"ຂະຫຍາຍ"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"ຫຍໍ້ລົງ"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"ໜ້າປົກອະລະບໍ້າ"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"ຕົວປັບລະດັບສຽງ"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"ບໍ່ໄດ້ເລືອກສື່ໃດ"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"ບໍ່ມີຂໍ້ມູນ"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"ກຳລັງສົ່ງສັນຍານພາບ"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-lt/strings.xml b/v7/mediarouter/src/main/res/values-lt/strings.xml
new file mode 100644
index 0000000..6f1ce9f
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-lt/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="6445173646164603280">"Sistema"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Įrenginiai"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Perdavimo mygtukas"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Perdavimo mygtukas. Atsijungta"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Perdavimo mygtukas. Prisijungiama"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Perdavimo mygtukas. Prisijungta"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Perduoti į"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Randami įrenginiai"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Atsijungti"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Sustabdyti perdavimą"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Uždaryti"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Leisti"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Pristabdyti"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Sustabdyti"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Išskleisti"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Sutraukti"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Albumo viršelis"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Garsumo šliaužiklis"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Nepasirinkta jokios medijos"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Informacija nepasiekiama"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Perduodamas ekranas"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-lv/strings.xml b/v7/mediarouter/src/main/res/values-lv/strings.xml
new file mode 100644
index 0000000..56432f8
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-lv/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="6445173646164603280">"Sistēma"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Ierīces"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Apraides poga"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Apraides poga. Savienojums pārtraukts."</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Apraides poga. Notiek savienojuma izveide."</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Apraides poga. Savienojums izveidots."</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Apraides veikšana uz ierīci"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Ierīču meklēšana"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Atvienot"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Apturēt apraidi"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Aizvērt"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Atskaņot"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Pauzēt"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Apturēt"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Izvērst"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Sakļaut"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Albuma vāciņš"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Skaļuma slīdnis"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Nav atlasīts multivides saturs"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Nav informācijas"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Notiek ekrāna apraide"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-mk/strings.xml b/v7/mediarouter/src/main/res/values-mk/strings.xml
new file mode 100644
index 0000000..e4572c5
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-mk/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="6445173646164603280">"Систем"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Уреди"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Копче за Cast"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Копче за Cast. Исклучено"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Копче за Cast. Се поврзува"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Копче за Cast. Поврзано"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Емитување на"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Се бараат уреди"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Исклучи"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Сопри со емитување"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Затвори"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Пушти"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Паузирај"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Сопри"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Прошири"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Собери"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Корица на албум"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Лизгач за јачина на звук"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Не се избрани аудиовизуелни датотеки"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Нема достапни информации"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Се емитува екран"</string>
+</resources>
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..d7c987b
--- /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="6445173646164603280">"സിസ്റ്റം"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"ഉപകരണങ്ങൾ"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"കാസ്റ്റ് ബട്ടൺ"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"കാസ്റ്റ് ബട്ടൺ. വിച്ഛേദിച്ചു"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"കാസ്‌റ്റ് ബട്ടൺ. കണക്‌റ്റ് ചെയ്യുന്നു"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"കാസ്റ്റ് ബട്ടൺ. കണക്‌റ്റ് ചെയ്തു"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"ഇതിലേക്ക് കാസ്‌റ്റ് ചെയ്യുക"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"ഉപകരണങ്ങൾ കണ്ടെത്തുന്നു"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"വിച്ഛേദിക്കുക"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"കാസ്റ്റ് ചെയ്യുന്നത് നിർത്തുക"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"അവസാനിപ്പിക്കുക"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"പ്ലേ ചെയ്യുക"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"താൽക്കാലികമായി നിർത്തുക"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"നിര്‍ത്തുക"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"വികസിപ്പിക്കുക"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"ചുരുക്കുക"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"ആൽബം ആർട്ട്"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"ശബ്‌ദ സ്ലൈഡർ"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"മീഡിയയൊന്നും തിരഞ്ഞെടുത്തിട്ടില്ല"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"വിവരങ്ങളൊന്നും ലഭ്യമല്ല"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"സ്‌ക്രീൻ കാസ്‌റ്റ് ചെയ്യുന്നു"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-mn/strings.xml b/v7/mediarouter/src/main/res/values-mn/strings.xml
new file mode 100644
index 0000000..9f03518
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-mn/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="6445173646164603280">"Систем"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Төхөөрөмж"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Дамжуулах товч"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Дамжуулах товч. Салсан"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Дамжуулах товч. Холбогдож байна"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Дамжуулах товч. Холбогдсон"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Дамжуулах"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Төхөөрөмжийг хайж байна"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Салгах"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Дамжуулахыг зогсоох"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Хаах"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Тоглуулах"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Түр зогсоох"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Зогсоох"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Дэлгэх"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Хумих"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Цомгийн зураг"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Дууны түвшин тааруулагч"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Ямар ч медиа сонгоогүй байна"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Мэдээлэл байхгүй байна"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Дэлгэцийг дамжуулж байна"</string>
+</resources>
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..f3ccbb9
--- /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="6445173646164603280">"सिस्टम"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"डिव्हाइस"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"कास्ट बटण"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"कास्ट बटण. डिस्कनेक्ट केले"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"कास्ट बटण. कनेक्ट करत आहे"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"कास्ट बटण. कनेक्ट केले"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"यावर कास्ट करा"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"डिव्हाइस शोधत आहे"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"‍डिस्कनेक्ट करा"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"कास्ट करणे थांबवा"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"बंद"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"खेळा"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"विराम द्या"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"थांबा"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"विस्तार करा"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"कोलॅप्स"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"अल्बम कला"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"व्हॉल्यूम स्लायडर"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"मीडिया निवडला नाही"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"कोणतीही माहिती उपलब्ध नाही"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"स्क्रीन कास्‍ट करत आहे"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-ms/strings.xml b/v7/mediarouter/src/main/res/values-ms/strings.xml
new file mode 100644
index 0000000..5096704
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-ms/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="6445173646164603280">"Sistem"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Peranti"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Butang hantar"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Butang hantar. Sambungan diputuskan"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Butang hantar. Menyambung"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Butang hantar. Disambungkan"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Hantar ke"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Mencari peranti"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Putuskan sambungan"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Berhenti menghantar"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Tutup"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Main"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Jeda"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Berhenti"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Kembangkan"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Runtuhkan"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Seni album"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Peluncur kelantangan"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Tiada media yang dipilih"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Maklumat tidak tersedia"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Menghantar skrin"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-my/strings.xml b/v7/mediarouter/src/main/res/values-my/strings.xml
new file mode 100644
index 0000000..5e843a0
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-my/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="6445173646164603280">"စနစ်"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"စက်များ"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"ကာစ်ခလုတ်"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"ကာစ်ခလုတ်။ ချိတ်ဆက်မထားပါ"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"ကာစ်ခလုတ်။ ချိတ်ဆက်နေသည်"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"ကာစ်ခလုတ်။ ချိတ်ဆက်ထားသည်"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"ဤစက်သို့ ကာစ်လုပ်ရန်"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"စက်များ ရှာနေသည်"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"ချိတ်ဆက်မှု ဖြုတ်ရန်"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"ကာစ်လုပ်ခြင်းကို ရပ်ရန်"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"ပိတ်ရန်"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"ဖွင့်ရန်"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"ခဏရပ်ရန်"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"ရပ်ရန်"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"ချဲ့ရန်"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"လျှော့ပြရန်"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"အယ်လ်ဘမ်ပုံ"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"အသံအတိုးအကျယ်ချိန်သည့် ဆလိုက်ဒါ"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"မီဒီယာ ရွေးမထားပါ"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"အချက်အလက် မရရှိနိုင်ပါ"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"ကာစ်တ်လုပ်သည့် မျက်နှာပြင်"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-nb/strings.xml b/v7/mediarouter/src/main/res/values-nb/strings.xml
new file mode 100644
index 0000000..487b9d5
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-nb/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="6445173646164603280">"System"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Enheter"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Cast-ikonet"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Cast-ikonet. Frakoblet"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Cast-ikonet. Kobler til"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Cast-ikonet. Tilkoblet"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Cast til"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Finner enheter"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Koble fra"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Stopp castingen"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Lukk"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Spill av"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Sett på pause"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Stopp"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Vis"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Skjul"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Albumgrafikk"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Glidebryter for volum"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Ingen medier er valgt"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Ingen informasjon er tilgjengelig"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Caster skjermen"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-ne/strings.xml b/v7/mediarouter/src/main/res/values-ne/strings.xml
new file mode 100644
index 0000000..8a13ac7
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-ne/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="6445173646164603280">"प्रणाली"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"यन्त्रहरू"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Cast बटन"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Cast बटन। जडान विच्छेद गरियो"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Cast बटन। जडान गरिँदै छ"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Cast बटन। जडान गरियो"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"यसमा Cast गर्नुहोस्"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"यन्त्रहरू पत्ता लगाइँदै छ"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"विच्छेद गर्नुहोस्"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Cast गर्न छाड्नुहोस्"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"बन्द गर्नुहोस्"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"प्ले गर्नुहोस्"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"पज गर्नुहोस्"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"रोक्नुहोस्"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"विस्तृत गर्नुहोस्"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"संक्षिप्त गर्नुहोस्"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"एल्बम आर्ट"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"भोल्युमको स्लाइडर"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"कुनै पनि मिडिया चयन गरिएन"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"कुनै पनि जानकारी उपलब्ध छैन"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"स्क्रिन Cast गरिँदै छ"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-nl/strings.xml b/v7/mediarouter/src/main/res/values-nl/strings.xml
new file mode 100644
index 0000000..eb19187
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-nl/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="6445173646164603280">"Systeem"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Apparaten"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Cast-knop"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Cast-icoon. Verbinding verbroken"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Cast-icoon. Verbinding maken"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Cast-icoon. Verbonden"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Casten naar"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Apparaten zoeken"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Loskoppelen"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Casten stoppen"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Sluiten"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Afspelen"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Pauzeren"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Stoppen"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Uitvouwen"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Samenvouwen"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Albumhoes"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Volumeschuifregelaar"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Geen media geselecteerd"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Geen informatie beschikbaar"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Scherm casten"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-pa/strings.xml b/v7/mediarouter/src/main/res/values-pa/strings.xml
new file mode 100644
index 0000000..5092ae0
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-pa/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="6445173646164603280">"ਸਿਸਟਮ"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"ਡੀਵਾਈਸ"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"\'ਕਾਸਟ ਕਰੋ\' ਬਟਨ"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"\'ਕਾਸਟ ਕਰੋ\' ਬਟਨ। ਡਿਸਕਨੈਕਟ ਕੀਤਾ ਗਿਆ"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"\'ਕਾਸਟ ਕਰੋ\' ਬਟਨ। ਕਨੈਕਟ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"\'ਕਾਸਟ ਕਰੋ\' ਬਟਨ। ਕਨੈਕਟ ਕੀਤਾ ਗਿਆ"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"ਏਥੇ ਕਾਸਟ ਕਰੋ"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"ਡੀਵਾਈਸ ਲੱਭੇ ਜਾ ਰਹੇ ਹਨ"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"ਡਿਸਕਨੈਕਟ ਕਰੋ"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"ਕਾਸਟ ਕਰਨਾ ਬੰਦ ਕਰੋ"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"ਬੰਦ ਕਰੋ"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"ਚਲਾਓ"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"ਰੋਕੋ"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"ਬੰਦ ਕਰੋ"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"ਵਿਸਤਾਰ ਕਰੋ"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"ਸਮੇਟੋ"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"ਐਲਬਮ ਕਲਾ"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"ਵੌਲਯੂਮ ਸਲਾਈਡਰ"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"ਕੋਈ ਮੀਡੀਆ ਨਹੀਂ ਚੁਣਿਆ ਗਿਆ"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"ਕੋਈ ਜਾਣਕਾਰੀ ਉਪਲਬਧ ਨਹੀਂ"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"ਸਕ੍ਰੀਨ \'ਤੇ ਕਾਸਟ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-pl/strings.xml b/v7/mediarouter/src/main/res/values-pl/strings.xml
new file mode 100644
index 0000000..6f52faf
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-pl/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="6445173646164603280">"System"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Urządzenia"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Przycisk Cast"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Przycisk Cast. Rozłączono"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Przycisk Cast. Łączę"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Przycisk Cast. Połączono"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Przesyłaj na"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Znajdowanie urządzeń"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Odłącz"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Zatrzymaj przesyłanie"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Zamknij"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Odtwórz"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Wstrzymaj"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Zatrzymaj"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Rozwiń"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Zwiń"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Okładka albumu"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Suwak głośności"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Nie wybrano multimediów"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Brak informacji"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Przesyłanie ekranu"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-pt-rBR/strings.xml b/v7/mediarouter/src/main/res/values-pt-rBR/strings.xml
new file mode 100644
index 0000000..213424a
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-pt-rBR/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="6445173646164603280">"Sistema"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Dispositivos"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Botão \"Transmitir\""</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Botão \"Transmitir\". Desconectado"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Botão \"Transmitir\". Conectando"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Botão \"Transmitir\". Conectado"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Transmitir para"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Localizando dispositivos"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Desconectar"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Parar transmissão"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Fechar"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Reproduzir"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Pausar"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Parar"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Expandir"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Recolher"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Arte do álbum"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Controle deslizante de volume"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Nenhuma mídia selecionada"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Nenhuma informação disponível"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Transmitindo tela"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-pt-rPT/strings.xml b/v7/mediarouter/src/main/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..4780144
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-pt-rPT/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="6445173646164603280">"Sistema"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Dispositivos"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Botão Transmitir"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Botão Transmitir. Desligado."</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Botão Transmitir. A ligar..."</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Botão Transmitir. Ligado"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Transmitir para"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"A localizar dispositivos..."</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Desligar"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Parar transmissão"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Fechar"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Reproduzir"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Interromper"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Parar"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Expandir"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Reduzir"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Imagem do álbum"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Controlo de deslize do volume"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Nenhum conteúdo multimédia selecionado."</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Nenhuma informação disponível."</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"A transmitir o ecrã..."</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-pt/strings.xml b/v7/mediarouter/src/main/res/values-pt/strings.xml
new file mode 100644
index 0000000..213424a
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-pt/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="6445173646164603280">"Sistema"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Dispositivos"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Botão \"Transmitir\""</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Botão \"Transmitir\". Desconectado"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Botão \"Transmitir\". Conectando"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Botão \"Transmitir\". Conectado"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Transmitir para"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Localizando dispositivos"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Desconectar"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Parar transmissão"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Fechar"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Reproduzir"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Pausar"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Parar"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Expandir"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Recolher"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Arte do álbum"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Controle deslizante de volume"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Nenhuma mídia selecionada"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Nenhuma informação disponível"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Transmitindo tela"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-ro/strings.xml b/v7/mediarouter/src/main/res/values-ro/strings.xml
new file mode 100644
index 0000000..82660fc
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-ro/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="6445173646164603280">"Sistem"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Dispozitive"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Butonul de proiecție"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Butonul de proiecție. Deconectat"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Butonul de proiecție. Se conectează"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Butonul de proiecție. Conectat"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Proiectați pe"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Se caută dispozitive"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Deconectați"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Nu mai proiectați"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Închideți"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Redați"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Întrerupeți"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Opriți"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Extindeți"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Restrângeți"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Grafica albumului"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Glisor pentru volum"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Niciun conținut media selectat"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Nu sunt disponibile informații"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Se proiectează ecranul"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-ru/strings.xml b/v7/mediarouter/src/main/res/values-ru/strings.xml
new file mode 100644
index 0000000..b3e5e16
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-ru/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="6445173646164603280">"Система"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Устройства"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Кнопка Google Cast"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Кнопка трансляции. Устройство отключено."</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Кнопка трансляции. Устройство подключается."</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Кнопка трансляции. Устройство подключено."</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Транслировать на устройство"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Поиск устройств…"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Отключить"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Прекратить трансляцию"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Закрыть"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Воспроизвести"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Пауза"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Остановить"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Развернуть"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Скрыть"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Обложка"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Регулятор громкости"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Контент не выбран"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Данных нет"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Подключение к удаленному монитору"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-si/strings.xml b/v7/mediarouter/src/main/res/values-si/strings.xml
new file mode 100644
index 0000000..044f1a3
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-si/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="6445173646164603280">"පද්ධතිය"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"උපාංග"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"විකාශ බොත්තම"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"විකාශ බොත්තම. විසන්ධි කරන ලදී"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"විකාශ බොත්තම සම්බන්ධ කරමින්"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"විකාශ බොත්තම සම්බන්ධ කරන ලදී"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"විකාශය"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"උපාංග සෙවීම"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"විසන්ධි කරන්න"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"විකාශය නවතන්න"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"වසන්න"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"ධාවනය කරන්න"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"විරාම කරන්න"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"නවත්වන්න"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"දිග හරින්න"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"හකුළන්න"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"ඇල්බම කලාව"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"හඬ පරිමා ස්ලයිඩරය"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"මාධ්‍ය තෝරා නැත"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"ලබා ගත හැකි තොරතුරු නොමැත"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"විකාශ තිරය"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-sk/strings.xml b/v7/mediarouter/src/main/res/values-sk/strings.xml
new file mode 100644
index 0000000..bb81d01
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-sk/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="6445173646164603280">"Systém"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Zariadenia"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Tlačidlo prenosu"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Tlačidlo prenosu. Odpojené"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Tlačidlo prenosu. Pripája sa"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Tlačidlo prenosu. Pripojené"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Prenos do zariadenia"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Hľadajú sa zariadenia"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Odpojiť"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Zastaviť prenos"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Zavrieť"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Prehrať"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Pozastaviť"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Ukončiť"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Rozbaliť"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Zbaliť"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Obrázok albumu"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Posúvač hlasitosti"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Nie sú vybrané žiadne médiá"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Nie sú k dispozícii žiadne informácie"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Prenáša sa obrazovka"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-sl/strings.xml b/v7/mediarouter/src/main/res/values-sl/strings.xml
new file mode 100644
index 0000000..2b0eeb8
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-sl/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="6445173646164603280">"Sistem"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Naprave"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Gumb za predvajanje"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Gumb za predvajanje. Povezava je prekinjena."</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Gumb za predvajanje. Vzpostavljanje povezave."</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Gumb za predvajanje. Povezava je vzpostavljena."</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Predvajanje prek:"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Iskanje naprav"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Prekini povezavo"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Ustavi predvajanje"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Zapri"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Predvajaj"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Začasno ustavi"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Ustavi"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Razširi"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Strni"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Naslovnica albuma"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Drsnik za glasnost"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Predstavnost ni izbrana"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Ni podatkov"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Predvajanje vsebine zaslona"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-sq/strings.xml b/v7/mediarouter/src/main/res/values-sq/strings.xml
new file mode 100644
index 0000000..f172212
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-sq/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="6445173646164603280">"Sistemi"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Pajisjet"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Butoni i transmetimit"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Butoni i transmetimit. Je i shkëputur"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Butoni i transmetimit. Po lidhet"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Butoni i transmetimit. Je i lidhur"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Transmeto te"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Po kërkon pajisje"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Shkëput"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Ndalo transmetimin"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Mbyll"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Luaj"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Pauzë"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Ndalo"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Zgjero"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Palos"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Kopertina e albumit"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Rrëshqitësi i volumit"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Nuk është zgjedhur asnjë media"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Nuk jepet asnjë informacion"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Po transmeton ekranin"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-sr/strings.xml b/v7/mediarouter/src/main/res/values-sr/strings.xml
new file mode 100644
index 0000000..e5d3577
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-sr/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="6445173646164603280">"Систем"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Уређаји"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Дугме Пребаци"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Дугме Пребаци. Веза је прекинута"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Дугме Пребаци. Повезује се"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Дугме Пребаци. Повезан је"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Пребаците на"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Траже се уређаји"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Прекини везу"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Заустави пребацивање"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Затвори"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Пусти"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Паузирај"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Заустави"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Прошири"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Скупи"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Омот албума"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Клизач за јачину звука"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Нема изабраних медија"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Нема доступних информација"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Пребацује се екран"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-sv/strings.xml b/v7/mediarouter/src/main/res/values-sv/strings.xml
new file mode 100644
index 0000000..3ed8212
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-sv/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="6445173646164603280">"System"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Enheter"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Cast-knappen"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Cast-knappen. Frånkopplad"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Cast-knappen. Ansluter"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Cast-knappen. Ansluten"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Casta till"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Letar efter enheter"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Koppla från"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Sluta casta"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Stäng"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Spela upp"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Pausa"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Stoppa"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Utöka"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Komprimera"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Skivomslag"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Volymreglage"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Ingen media har valts"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Det finns ingen information"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Skärmen castas"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-sw/strings.xml b/v7/mediarouter/src/main/res/values-sw/strings.xml
new file mode 100644
index 0000000..2a7af85
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-sw/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="6445173646164603280">"Mfumo"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Vifaa"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Kitufe cha kutuma"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Kitufe cha kutuma. Kimeondolewa"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Kitufe cha kutuma. Kinaunganishwa"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Kitufe cha kutuma. Kimeunganishwa"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Tuma kwenye"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Inatafuta vifaa"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Ondoa"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Acha kutuma"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Funga"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Cheza"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Sitisha"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Simamisha"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Panua"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Kunja"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Sanaa ya albamu"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Kidhibiti cha sauti"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Hakuna maudhui yaliyochaguliwa"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Hakuna maelezo yaliyopatikana"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Inatuma skrini"</string>
+</resources>
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..6b4f896
--- /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="6445173646164603280">"சிஸ்டம்"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"சாதனங்கள்"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"அலைபரப்பும் பட்டன்"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"அலைபரப்பும் பட்டன். துண்டிக்கப்பட்டது"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"அலைபரப்பும் பட்டன். இணைக்கிறது"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"அலைபரப்பும் பட்டன். இணைக்கப்பட்டது"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"இதற்கு அலைபரப்பு:"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"சாதனங்களைத் தேடுகிறது"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"துண்டி"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"அலைபரப்புவதை நிறுத்து"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"மூடுவதற்கான பட்டன்"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"இயக்குவதற்கான பட்டன்"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"இடைநிறுத்துவதற்கான பட்டன்"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"நிறுத்துவதற்கான பட்டன்"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"விரிவாக்குவதற்கான பட்டன்"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"சுருக்குவதற்கான பட்டன்"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"ஆல்பம் ஆர்ட்"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"ஒலியளவு ஸ்லைடர்"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"மீடியா எதுவும் தேர்ந்தெடுக்கப்படவில்லை"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"தகவல் எதுவுமில்லை"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"திரையை அலைபரப்புகிறது"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-te/strings.xml b/v7/mediarouter/src/main/res/values-te/strings.xml
new file mode 100644
index 0000000..0d4168f
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-te/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="6445173646164603280">"సిస్టమ్"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"పరికరాలు"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Cast బటన్"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Cast బటన్. డిస్‌కనెక్ట్ చేయబడింది"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Cast బటన్. కనెక్ట్ చేస్తోంది"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Cast బటన్. కనెక్ట్ చేయబడింది"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"దీనికి ప్రసారం చేయండి"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"పరికరాలను కనుగొంటోంది"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"డిస్‌కనెక్ట్ చేయి"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"ప్రసారాన్ని ఆపివేయి"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"మూసివేయి"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"ప్లే చేయి"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"పాజ్ చేయి"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"ఆపివేయి"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"విస్తరించు"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"కుదించు"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"ఆల్బమ్ ఆర్ట్"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"వాల్యూమ్ స్లయిడర్"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"మీడియా ఏదీ ఎంచుకోలేదు"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"సమాచారం అందుబాటులో లేదు"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"స్క్రీన్‌ను ప్రసారం చేస్తోంది"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-th/strings.xml b/v7/mediarouter/src/main/res/values-th/strings.xml
new file mode 100644
index 0000000..b360779
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-th/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="6445173646164603280">"ระบบ"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"อุปกรณ์"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"ปุ่ม \"แคสต์\""</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"ปุ่ม \"แคสต์\" ยกเลิกการเชื่อมต่อแล้ว"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"ปุ่ม \"แคสต์\" กำลังเชื่อมต่อ"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"ปุ่ม \"แคสต์\" เชื่อมต่อแล้ว"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"แคสต์ไปยัง"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"กำลังค้นหาอุปกรณ์"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"ยกเลิกการเชื่อมต่อ"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"หยุดแคสต์"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"ปิด"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"เล่น"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"หยุดชั่วคราว"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"หยุด"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"ขยาย"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"ยุบ"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"ปกอัลบั้ม"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"แถบเลื่อนปรับระดับเสียง"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"ไม่ได้เลือกสื่อไว้"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"ไม่มีข้อมูล"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"กำลังแคสต์หน้าจอ"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-tl/strings.xml b/v7/mediarouter/src/main/res/values-tl/strings.xml
new file mode 100644
index 0000000..4d21125
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-tl/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="6445173646164603280">"System"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Mga Device"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Button na I-cast"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Button na I-cast. Nadiskonekta"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Button na I-cast. Kumokonekta"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Button na I-cast. Nakakonekta"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"I-cast sa"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Naghahanap ng mga device"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Idiskonekta"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Ihinto ang pag-cast"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Isara"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"I-play"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"I-pause"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Ihinto"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"I-expand"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"I-collapse"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Album art"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Slider ng volume"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Walang napiling media"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Walang available na impormasyon"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Ikina-cast ang screen"</string>
+</resources>
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..e44f443
--- /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="6445173646164603280">"Sistem"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Cihazlar"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Yayınla düğmesi"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Yayınla düğmesi. Bağlantı kesildi"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Yayınla düğmesi. Bağlanıyor"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Yayınla düğmesi. Bağlandı"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Şuraya yayınla:"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Cihazlar bulunuyor"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Bağlantıyı kes"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Yayını durdur"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Kapat"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Oynat"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Duraklat"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Durdur"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Genişlet"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Daralt"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Albüm kapağı"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Ses düzeyi kaydırma çubuğu"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Medya seçilmedi"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Bilgi yok"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Ekran yayınlanıyor"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-uk/strings.xml b/v7/mediarouter/src/main/res/values-uk/strings.xml
new file mode 100644
index 0000000..28e09bd
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-uk/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="6445173646164603280">"Система"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Пристрої"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Кнопка трансляції"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Кнопка трансляції. Від’єднано"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Кнопка трансляції. Під’єднання"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Кнопка трансляції. Під’єднано"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Транслювати на"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Пошук пристроїв"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Від’єднати"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Припинити трансляцію"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Закрити"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Відтворити"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Призупинити"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Припинити"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Розгорнути"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Згорнути"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Обкладинка альбому"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Повзунок гучності"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Не вибрано медіа"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Немає даних"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Трансляція екрана"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-ur/strings.xml b/v7/mediarouter/src/main/res/values-ur/strings.xml
new file mode 100644
index 0000000..8c09830
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-ur/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="6445173646164603280">"سسٹم"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"آلات"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"کاسٹ کرنے کا بٹن"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"کاسٹ کرنے کا بٹن۔ غیر منسلک ہے"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"کاسٹ کرنے کا بٹن۔ منسلک ہو رہا ہے"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"کاسٹ کرنے کا بٹن۔ منسلک ہے"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"اس میں کاسٹ کریں"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"آلات تلاش کئے جا رہے ہیں"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"غیر منسلک کریں"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"کاسٹ کرنا بند کریں"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"بند کریں"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"چلائیں"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"موقوف کریں"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"روکیں"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"پھیلائیں"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"سکیڑیں"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"البم آرٹ"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"والیوم سلائیڈر"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"کوئی میڈیا منتخب نہیں ہے"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"کوئی معلومات دستیاب نہیں"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"اسکرین کاسٹ ہو رہی ہے"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-uz/strings.xml b/v7/mediarouter/src/main/res/values-uz/strings.xml
new file mode 100644
index 0000000..2eadc9b
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-uz/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="6445173646164603280">"Tizim"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Qurilmalar"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Translatsiya qilish tugmasi"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Translatsiya tugmasi. Uzildi"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Translatsiya tugmasi. Ulanmoqda"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Translatsiya tugmasi. Ulandi"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Bunga translatsiya qilish:"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Qurilmalarni topish"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Uzish"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Translatsiyani to‘xtatish"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Yopish"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Ijro"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Pauza"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"To‘xtatish"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Yoyish"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Yig‘ish"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Albom muqovasi"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Tovush balandligi slayderi"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Multimedia tanlamagan"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Ma’lumot yo‘q"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Ekran namoyish qilinmoqda"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-vi/strings.xml b/v7/mediarouter/src/main/res/values-vi/strings.xml
new file mode 100644
index 0000000..d0f7311
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-vi/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="6445173646164603280">"Hệ thống"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Thiết bị"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Nút truyền"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Nút truyền. Đã ngắt kết nối"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Nút truyền. Đang kết nối"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Nút truyền. Đã kết nối"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Truyền tới"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Đang tìm thiết bị"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Ngắt kết nối"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Dừng truyền"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Đóng"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Phát"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Tạm dừng"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Dừng"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Mở rộng"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Thu gọn"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Ảnh bìa album"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Thanh trượt âm lượng"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Không có phương tiện nào được chọn"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Không có thông tin nào"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Đang truyền màn hình"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-zh-rCN/strings.xml b/v7/mediarouter/src/main/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..140c817
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-zh-rCN/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="6445173646164603280">"系统"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"设备"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"投射按钮"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"投射按钮。已断开连接"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"投射按钮。正在连接"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"投射按钮。已连接"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"投射到"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"正在查找设备"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"断开连接"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"停止投射"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"关闭"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"播放"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"暂停"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"停止"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"展开"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"收起"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"专辑封面"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"音量滑块"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"未选择任何媒体内容"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"没有任何相关信息"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"正在投射屏幕"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-zh-rHK/strings.xml b/v7/mediarouter/src/main/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..9318093
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-zh-rHK/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="6445173646164603280">"系統"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"裝置"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"投放按鈕"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"投放按鈕。解除咗連線"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"投放按鈕。連緊線"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"投放按鈕。連咗線"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"投放至"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"正在尋找裝置"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"解除連線"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"停止投放"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"閂"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"播放"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"暫停"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"停"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"展開"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"收合"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"專輯封面"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"音量滑桿"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"未選取任何媒體"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"沒有資料可以提供"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"正在投放畫面"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-zh-rTW/strings.xml b/v7/mediarouter/src/main/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..bd2f9ad
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-zh-rTW/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="6445173646164603280">"系統"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"裝置"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"投放按鈕"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"投放按鈕;已中斷連線"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"投放按鈕;連線中"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"投放按鈕;已連線"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"投放到"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"正在尋找裝置"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"中斷連線"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"停止投放"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"關閉"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"播放"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"暫停"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"停止"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"展開"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"收合"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"專輯封面"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"音量滑桿"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"未選取任何媒體"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"沒有可用的資訊"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"正在投放畫面"</string>
+</resources>
diff --git a/v7/mediarouter/src/main/res/values-zu/strings.xml b/v7/mediarouter/src/main/res/values-zu/strings.xml
new file mode 100644
index 0000000..e91293f
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-zu/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="6445173646164603280">"Isistimu"</string>
+    <string name="mr_user_route_category_name" msgid="8951247913519682277">"Amadivayisi"</string>
+    <string name="mr_button_content_description" msgid="6209940985205889239">"Inkinobho yokusakaza"</string>
+    <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Inkinobho yokusakaza. Kunqanyuliwe"</string>
+    <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Inkinobho yokusakaza. Kuyaxhunywa"</string>
+    <string name="mr_cast_button_connected" msgid="7205934955575650355">"Inkinobho yokusakaza. Kuxhunyiwe"</string>
+    <string name="mr_chooser_title" msgid="1469819231928206099">"Sakaza ku-"</string>
+    <string name="mr_chooser_searching" msgid="7883700464756247478">"Ithola amadivayisi"</string>
+    <string name="mr_controller_disconnect" msgid="1224563715954797152">"Nqamula"</string>
+    <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Misa ukusakaza"</string>
+    <string name="mr_controller_close_description" msgid="1404151965680505956">"Vala"</string>
+    <string name="mr_controller_play" msgid="2233159395781515552">"Dlala"</string>
+    <string name="mr_controller_pause" msgid="5465089322498973309">"Misa isikhashana"</string>
+    <string name="mr_controller_stop" msgid="6970507798830838731">"Misa"</string>
+    <string name="mr_controller_expand_group" msgid="6561849209271950311">"Nweba"</string>
+    <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Goqa"</string>
+    <string name="mr_controller_album_art" msgid="8313236767081989488">"Ubuciko be-albhamu"</string>
+    <string name="mr_controller_volume_slider" msgid="390328956880221771">"Isilayida sevolumu"</string>
+    <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Ayikho imidiya ekhethiwe"</string>
+    <string name="mr_controller_no_info_available" msgid="942251150039480236">"Alukho ulwazi olutholakalayo"</string>
+    <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Isikrini sokusakaza"</string>
+</resources>
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/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/java/android/support/v7/graphics/Palette.java b/v7/palette/src/main/java/android/support/v7/graphics/Palette.java
index e716fb5..6e816bf 100644
--- a/v7/palette/src/main/java/android/support/v7/graphics/Palette.java
+++ b/v7/palette/src/main/java/android/support/v7/graphics/Palette.java
@@ -23,6 +23,7 @@
 import android.support.annotation.ColorInt;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
+import android.support.annotation.Px;
 import android.support.v4.graphics.ColorUtils;
 import android.support.v4.util.ArrayMap;
 import android.util.Log;
@@ -731,7 +732,7 @@
          * @param bottom The bottom of the rectangle used for the region.
          */
         @NonNull
-        public Builder setRegion(int left, int top, int right, int bottom) {
+        public Builder setRegion(@Px int left, @Px int top, @Px int right, @Px int bottom) {
             if (mBitmap != null) {
                 if (mRegion == null) mRegion = new Rect();
                 // Set the Rect to be initially the whole Bitmap
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/res/values-af/strings.xml b/v7/preference/res/values-af/strings.xml
new file mode 100644
index 0000000..17c2037
--- /dev/null
+++ b/v7/preference/res/values-af/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"AAN"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"AF"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Gevorderd"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-am/strings.xml b/v7/preference/res/values-am/strings.xml
new file mode 100644
index 0000000..052425c
--- /dev/null
+++ b/v7/preference/res/values-am/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"በርቷል"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"ቅናሽ"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"የላቀ"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>፣ <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-ar/strings.xml b/v7/preference/res/values-ar/strings.xml
new file mode 100644
index 0000000..1e5515d
--- /dev/null
+++ b/v7/preference/res/values-ar/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"تفعيل"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"إيقاف"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"إعدادات متقدمة"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>، <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-az/strings.xml b/v7/preference/res/values-az/strings.xml
new file mode 100644
index 0000000..978b862
--- /dev/null
+++ b/v7/preference/res/values-az/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"AKTİV"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"DEAKTİV"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Qabaqcıl"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-b+sr+Latn/strings.xml b/v7/preference/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..61c784a
--- /dev/null
+++ b/v7/preference/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"UKLJUČENO"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"ISKLJUČENO"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Napredno"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-be/strings.xml b/v7/preference/res/values-be/strings.xml
new file mode 100644
index 0000000..8ebdeaf
--- /dev/null
+++ b/v7/preference/res/values-be/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"УКЛ."</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"ВЫКЛ."</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Высокая"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-bg/strings.xml b/v7/preference/res/values-bg/strings.xml
new file mode 100644
index 0000000..e2e9544
--- /dev/null
+++ b/v7/preference/res/values-bg/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"ВКЛ."</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"ИЗКЛ."</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Разширени"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-bn/strings.xml b/v7/preference/res/values-bn/strings.xml
new file mode 100644
index 0000000..a17e22a
--- /dev/null
+++ b/v7/preference/res/values-bn/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"চালু"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"বন্ধ"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"উন্নত"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-bs/strings.xml b/v7/preference/res/values-bs/strings.xml
new file mode 100644
index 0000000..61c784a
--- /dev/null
+++ b/v7/preference/res/values-bs/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"UKLJUČENO"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"ISKLJUČENO"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Napredno"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-ca/strings.xml b/v7/preference/res/values-ca/strings.xml
new file mode 100644
index 0000000..56e5c66
--- /dev/null
+++ b/v7/preference/res/values-ca/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"ACTIVAT"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"DESACTIVAT"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Opcions avançades"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-cs/strings.xml b/v7/preference/res/values-cs/strings.xml
new file mode 100644
index 0000000..5865c0b
--- /dev/null
+++ b/v7/preference/res/values-cs/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"ZAP"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"VYP"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Rozšířené"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-da/strings.xml b/v7/preference/res/values-da/strings.xml
new file mode 100644
index 0000000..da2532f
--- /dev/null
+++ b/v7/preference/res/values-da/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"TIL"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"FRA"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Avanceret"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-de/strings.xml b/v7/preference/res/values-de/strings.xml
new file mode 100644
index 0000000..5b0be51
--- /dev/null
+++ b/v7/preference/res/values-de/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"AN"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"AUS"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Erweitert"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-el/strings.xml b/v7/preference/res/values-el/strings.xml
new file mode 100644
index 0000000..59ba395
--- /dev/null
+++ b/v7/preference/res/values-el/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"ΕΝΕΡΓΟΠΟΙΗΣΗ"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"ΑΠΕΝΕΡΓΟΠΟΙΗΣΗ"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Σύνθετες"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-en-rAU/strings.xml b/v7/preference/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000..dd3e15f
--- /dev/null
+++ b/v7/preference/res/values-en-rAU/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"ON"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"OFF"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Advanced"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-en-rCA/strings.xml b/v7/preference/res/values-en-rCA/strings.xml
new file mode 100644
index 0000000..dd3e15f
--- /dev/null
+++ b/v7/preference/res/values-en-rCA/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"ON"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"OFF"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Advanced"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-en-rGB/strings.xml b/v7/preference/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..dd3e15f
--- /dev/null
+++ b/v7/preference/res/values-en-rGB/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"ON"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"OFF"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Advanced"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-en-rIN/strings.xml b/v7/preference/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..dd3e15f
--- /dev/null
+++ b/v7/preference/res/values-en-rIN/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"ON"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"OFF"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Advanced"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-en-rXC/strings.xml b/v7/preference/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000..3f4c7a0
--- /dev/null
+++ b/v7/preference/res/values-en-rXC/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‏‎‎‏‏‎‏‎‎‏‎‏‎‎‎‎‎‏‏‎‎‎‏‎‏‎‎‎‎‏‎‏‏‎‎‎‎‎‎‏‏‎‎‏‎‎‏‎‎‏‏‎‎‎ON‎‏‎‎‏‎"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‏‏‏‎‎‏‏‎‎‎‎‏‏‎‎‏‎‎‏‎‎‎‏‏‏‏‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‎‏‏‎‏‎‏‏‎‏‏‎‏‏‎‎OFF‎‏‎‎‏‎"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‏‎‏‎‏‎‎‎‏‎‎‏‏‏‏‎‏‎‎‏‎‎‏‎‏‎‎‎‎‏‎‏‎‎‎‏‏‎‎‎‎‎‏‏‏‏‎‎‏‏‏‏‏‏‏‎‎‎Advanced‎‏‎‎‏‎"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‏‏‎‏‏‏‏‎‏‏‏‏‏‎‏‏‎‎‎‏‎‎‏‏‏‏‏‎‏‎‏‏‏‎‎‏‎‏‏‎‎‏‏‎‏‎‏‎‎‎‎‎‎‏‏‎‎‏‎‎‏‏‎<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>‎‏‎‎‏‏‏‎, ‎‏‎‎‏‏‎<xliff:g id="ADDED_ITEMS">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+</resources>
diff --git a/v7/preference/res/values-es-rUS/strings.xml b/v7/preference/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..3911ab9
--- /dev/null
+++ b/v7/preference/res/values-es-rUS/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"ACTIVADO"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"DESACTIVADO"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Avanzado"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-es/strings.xml b/v7/preference/res/values-es/strings.xml
new file mode 100644
index 0000000..3911ab9
--- /dev/null
+++ b/v7/preference/res/values-es/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"ACTIVADO"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"DESACTIVADO"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Avanzado"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-et/strings.xml b/v7/preference/res/values-et/strings.xml
new file mode 100644
index 0000000..9fa4f4f
--- /dev/null
+++ b/v7/preference/res/values-et/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"SEES"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"VÄLJAS"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Täpsemad"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-eu/strings.xml b/v7/preference/res/values-eu/strings.xml
new file mode 100644
index 0000000..6718992
--- /dev/null
+++ b/v7/preference/res/values-eu/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"AKTIBATUTA"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"DESAKTIBATUTA"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Aurreratua"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-fa/strings.xml b/v7/preference/res/values-fa/strings.xml
new file mode 100644
index 0000000..86e9f30
--- /dev/null
+++ b/v7/preference/res/values-fa/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"روشن"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"خاموش"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"پیشرفته"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>، <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-fi/strings.xml b/v7/preference/res/values-fi/strings.xml
new file mode 100644
index 0000000..cec0857
--- /dev/null
+++ b/v7/preference/res/values-fi/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"PÄÄLLÄ"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"POIS PÄÄLTÄ"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Lisätiedot"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-fr-rCA/strings.xml b/v7/preference/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..db4c2b5
--- /dev/null
+++ b/v7/preference/res/values-fr-rCA/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"ACTIVÉ"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"DÉSACTIVÉ"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Avancé"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-fr/strings.xml b/v7/preference/res/values-fr/strings.xml
new file mode 100644
index 0000000..b5cca98
--- /dev/null
+++ b/v7/preference/res/values-fr/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"ACTIVÉ"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"DÉSACTIVÉ"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Options avancées"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-gl/strings.xml b/v7/preference/res/values-gl/strings.xml
new file mode 100644
index 0000000..3911ab9
--- /dev/null
+++ b/v7/preference/res/values-gl/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"ACTIVADO"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"DESACTIVADO"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Avanzado"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-gu/strings.xml b/v7/preference/res/values-gu/strings.xml
new file mode 100644
index 0000000..468fd2c
--- /dev/null
+++ b/v7/preference/res/values-gu/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"ચાલુ"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"બંધ"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"વિગતવાર"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-hi/strings.xml b/v7/preference/res/values-hi/strings.xml
new file mode 100644
index 0000000..dcfb766
--- /dev/null
+++ b/v7/preference/res/values-hi/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"चालू"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"बंद"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"बेहतर विकल्प"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-hr/strings.xml b/v7/preference/res/values-hr/strings.xml
new file mode 100644
index 0000000..61c784a
--- /dev/null
+++ b/v7/preference/res/values-hr/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"UKLJUČENO"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"ISKLJUČENO"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Napredno"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-hu/strings.xml b/v7/preference/res/values-hu/strings.xml
new file mode 100644
index 0000000..85f80aa
--- /dev/null
+++ b/v7/preference/res/values-hu/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"BE"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"KI"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Speciális"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-hy/strings.xml b/v7/preference/res/values-hy/strings.xml
new file mode 100644
index 0000000..06f9d22
--- /dev/null
+++ b/v7/preference/res/values-hy/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"ՄԻԱՑՎԱԾ"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"ԱՆՋԱՏԱԾ"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Լրացուցիչ"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-in/strings.xml b/v7/preference/res/values-in/strings.xml
new file mode 100644
index 0000000..e17c251
--- /dev/null
+++ b/v7/preference/res/values-in/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"AKTIF"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"NONAKTIF"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Lanjutan"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-is/strings.xml b/v7/preference/res/values-is/strings.xml
new file mode 100644
index 0000000..361d1c3
--- /dev/null
+++ b/v7/preference/res/values-is/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"KVEIKT"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"SLÖKKT"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Ítarlegt"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-it/strings.xml b/v7/preference/res/values-it/strings.xml
new file mode 100644
index 0000000..2514600
--- /dev/null
+++ b/v7/preference/res/values-it/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"ON"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"OFF"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Avanzate"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-iw/strings.xml b/v7/preference/res/values-iw/strings.xml
new file mode 100644
index 0000000..6ca15e5
--- /dev/null
+++ b/v7/preference/res/values-iw/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"מופעל"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"כבוי"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"מתקדם"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-ja/strings.xml b/v7/preference/res/values-ja/strings.xml
new file mode 100644
index 0000000..2d599d3
--- /dev/null
+++ b/v7/preference/res/values-ja/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"ON"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"OFF"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"詳細設定"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>、<xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-ka/strings.xml b/v7/preference/res/values-ka/strings.xml
new file mode 100644
index 0000000..21b8246
--- /dev/null
+++ b/v7/preference/res/values-ka/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"ჩართული"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"გამორთული"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"დამატებით"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-kk/strings.xml b/v7/preference/res/values-kk/strings.xml
new file mode 100644
index 0000000..ebbba78
--- /dev/null
+++ b/v7/preference/res/values-kk/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"ҚОСУЛЫ"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"ӨШІРУЛІ"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Қосымша"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-km/strings.xml b/v7/preference/res/values-km/strings.xml
new file mode 100644
index 0000000..d7cb942
--- /dev/null
+++ b/v7/preference/res/values-km/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"បើក"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"បិទ"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"កម្រិតខ្ពស់"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-kn/strings.xml b/v7/preference/res/values-kn/strings.xml
new file mode 100644
index 0000000..9ce1917
--- /dev/null
+++ b/v7/preference/res/values-kn/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"ಆನ್"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"ಆಫ್"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"ಸುಧಾರಿತ"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-ko/strings.xml b/v7/preference/res/values-ko/strings.xml
new file mode 100644
index 0000000..ab1f380
--- /dev/null
+++ b/v7/preference/res/values-ko/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"사용"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"사용 안함"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"고급"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-ky/strings.xml b/v7/preference/res/values-ky/strings.xml
new file mode 100644
index 0000000..257c6d5
--- /dev/null
+++ b/v7/preference/res/values-ky/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"КҮЙҮК"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"ӨЧҮК"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Өркүндөтүлгөн"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-lo/strings.xml b/v7/preference/res/values-lo/strings.xml
new file mode 100644
index 0000000..f4c1e2d
--- /dev/null
+++ b/v7/preference/res/values-lo/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"ເປີດ"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"ປິດ"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"ຂັ້ນສູງ"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-lt/strings.xml b/v7/preference/res/values-lt/strings.xml
new file mode 100644
index 0000000..ef1bfd6
--- /dev/null
+++ b/v7/preference/res/values-lt/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"Įjungta"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"Išjungta"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Išplėstinės"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-lv/strings.xml b/v7/preference/res/values-lv/strings.xml
new file mode 100644
index 0000000..e4890b1
--- /dev/null
+++ b/v7/preference/res/values-lv/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"IESLĒGTS"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"IZSLĒGTS"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Papildu"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-mk/strings.xml b/v7/preference/res/values-mk/strings.xml
new file mode 100644
index 0000000..f276876
--- /dev/null
+++ b/v7/preference/res/values-mk/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"ВКЛУЧЕНО"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"ИСКЛУЧЕНО"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Напредно"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-ml/strings.xml b/v7/preference/res/values-ml/strings.xml
new file mode 100644
index 0000000..83d1125
--- /dev/null
+++ b/v7/preference/res/values-ml/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"ഓൺ"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"ഓഫ്"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"വിപുലമായത്"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-mn/strings.xml b/v7/preference/res/values-mn/strings.xml
new file mode 100644
index 0000000..2d20950
--- /dev/null
+++ b/v7/preference/res/values-mn/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"АСААЛТТАЙ"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"УНТРААТАЙ"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Нарийвчилсан"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-mr/strings.xml b/v7/preference/res/values-mr/strings.xml
new file mode 100644
index 0000000..1e492dd
--- /dev/null
+++ b/v7/preference/res/values-mr/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"चालू"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"बंद"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"प्रगत"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-ms/strings.xml b/v7/preference/res/values-ms/strings.xml
new file mode 100644
index 0000000..1601d8a
--- /dev/null
+++ b/v7/preference/res/values-ms/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"HIDUP"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"MATI"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Lanjutan"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-my/strings.xml b/v7/preference/res/values-my/strings.xml
new file mode 100644
index 0000000..77237bc
--- /dev/null
+++ b/v7/preference/res/values-my/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"ဖွင့်ရန်"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"ပိတ်ရန်"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"အဆင့်မြင့်"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>၊ <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-nb/strings.xml b/v7/preference/res/values-nb/strings.xml
new file mode 100644
index 0000000..d5c814b
--- /dev/null
+++ b/v7/preference/res/values-nb/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"PÅ"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"AV"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Avansert"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-ne/strings.xml b/v7/preference/res/values-ne/strings.xml
new file mode 100644
index 0000000..1da1f25
--- /dev/null
+++ b/v7/preference/res/values-ne/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"सक्रिय छ"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"निष्क्रिय छ"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"उन्नत"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-nl/strings.xml b/v7/preference/res/values-nl/strings.xml
new file mode 100644
index 0000000..dc84ab8
--- /dev/null
+++ b/v7/preference/res/values-nl/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"AAN"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"UIT"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Geavanceerd"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-pa/strings.xml b/v7/preference/res/values-pa/strings.xml
new file mode 100644
index 0000000..29471c3
--- /dev/null
+++ b/v7/preference/res/values-pa/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"ਚਾਲੂ"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"ਬੰਦ"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"ਉੱਨਤ"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-pl/strings.xml b/v7/preference/res/values-pl/strings.xml
new file mode 100644
index 0000000..ef7bbf8
--- /dev/null
+++ b/v7/preference/res/values-pl/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"WŁ."</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"WYŁ."</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Zaawansowane"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-pt-rBR/strings.xml b/v7/preference/res/values-pt-rBR/strings.xml
new file mode 100644
index 0000000..433e8e3
--- /dev/null
+++ b/v7/preference/res/values-pt-rBR/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"ATIVADO"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"DESATIVADO"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Avançado"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-pt-rPT/strings.xml b/v7/preference/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..4f296f6
--- /dev/null
+++ b/v7/preference/res/values-pt-rPT/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"ATIVADA"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"DESATIVADA"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Avançadas"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-pt/strings.xml b/v7/preference/res/values-pt/strings.xml
new file mode 100644
index 0000000..433e8e3
--- /dev/null
+++ b/v7/preference/res/values-pt/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"ATIVADO"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"DESATIVADO"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Avançado"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-ro/strings.xml b/v7/preference/res/values-ro/strings.xml
new file mode 100644
index 0000000..1353a6f
--- /dev/null
+++ b/v7/preference/res/values-ro/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"ACTIVAT"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"DEZACTIVAT"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Avansat"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-ru/strings.xml b/v7/preference/res/values-ru/strings.xml
new file mode 100644
index 0000000..8449700
--- /dev/null
+++ b/v7/preference/res/values-ru/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"ВКЛ."</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"ВЫКЛ."</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Дополнительно"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-si/strings.xml b/v7/preference/res/values-si/strings.xml
new file mode 100644
index 0000000..27bf118
--- /dev/null
+++ b/v7/preference/res/values-si/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"ක්‍රියාත්මකයි"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"ක්‍රියාවිරහිතයි"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"උසස්"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-sk/strings.xml b/v7/preference/res/values-sk/strings.xml
new file mode 100644
index 0000000..a087a8b
--- /dev/null
+++ b/v7/preference/res/values-sk/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"ZAP."</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"VYP."</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Rozšírené"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-sl/strings.xml b/v7/preference/res/values-sl/strings.xml
new file mode 100644
index 0000000..887c1b1
--- /dev/null
+++ b/v7/preference/res/values-sl/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"VKLOPLJENO"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"IZKLOPLJENO"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Dodatno"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-sq/strings.xml b/v7/preference/res/values-sq/strings.xml
new file mode 100644
index 0000000..f2f5b77
--- /dev/null
+++ b/v7/preference/res/values-sq/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"AKTIV"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"JOAKTIV"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Të përparuara"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-sr/strings.xml b/v7/preference/res/values-sr/strings.xml
new file mode 100644
index 0000000..322ace5
--- /dev/null
+++ b/v7/preference/res/values-sr/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"УКЉУЧЕНО"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"ИСКЉУЧЕНО"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Напредно"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-sv/strings.xml b/v7/preference/res/values-sv/strings.xml
new file mode 100644
index 0000000..c689ea1
--- /dev/null
+++ b/v7/preference/res/values-sv/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"PÅ"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"AV"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Avancerat"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-sw/strings.xml b/v7/preference/res/values-sw/strings.xml
new file mode 100644
index 0000000..9010663
--- /dev/null
+++ b/v7/preference/res/values-sw/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"IMEWASHWA"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"IMEZIMWA"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Mipangilio ya Kina"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-ta/strings.xml b/v7/preference/res/values-ta/strings.xml
new file mode 100644
index 0000000..9fc536d
--- /dev/null
+++ b/v7/preference/res/values-ta/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"ஆன் செய்"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"ஆஃப் செய்"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"மேம்பட்டது"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-te/strings.xml b/v7/preference/res/values-te/strings.xml
new file mode 100644
index 0000000..7277c76
--- /dev/null
+++ b/v7/preference/res/values-te/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"ఆన్"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"ఆఫ్"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"అధునాతనం"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-th/strings.xml b/v7/preference/res/values-th/strings.xml
new file mode 100644
index 0000000..90a5433
--- /dev/null
+++ b/v7/preference/res/values-th/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"เปิด"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"ปิด"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"ขั้นสูง"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g> <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-tl/strings.xml b/v7/preference/res/values-tl/strings.xml
new file mode 100644
index 0000000..5b6885b
--- /dev/null
+++ b/v7/preference/res/values-tl/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"NAKA-ON"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"NAKA-OFF"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Advanced"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-tr/strings.xml b/v7/preference/res/values-tr/strings.xml
new file mode 100644
index 0000000..fa66179
--- /dev/null
+++ b/v7/preference/res/values-tr/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"AÇIK"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"KAPALI"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Gelişmiş"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-uk/strings.xml b/v7/preference/res/values-uk/strings.xml
new file mode 100644
index 0000000..47280c3
--- /dev/null
+++ b/v7/preference/res/values-uk/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"УВІМКНЕНО"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"ВИМКНЕНО"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Додатково"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-ur/strings.xml b/v7/preference/res/values-ur/strings.xml
new file mode 100644
index 0000000..c304b12
--- /dev/null
+++ b/v7/preference/res/values-ur/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"آن"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"آف"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"جدید ترین"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>، <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-uz/strings.xml b/v7/preference/res/values-uz/strings.xml
new file mode 100644
index 0000000..6730b74
--- /dev/null
+++ b/v7/preference/res/values-uz/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"YONIQ"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"O‘CHIQ"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Ekspert"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-vi/strings.xml b/v7/preference/res/values-vi/strings.xml
new file mode 100644
index 0000000..d8ea12b
--- /dev/null
+++ b/v7/preference/res/values-vi/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"BẬT"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"TẮT"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Nâng cao"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-zh-rCN/strings.xml b/v7/preference/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..3f91ed6
--- /dev/null
+++ b/v7/preference/res/values-zh-rCN/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"开启"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"关闭"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"高级"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"当前显示了 <xliff:g id="CURRENT_ITEMS">%1$s</xliff:g> 项(已添加 <xliff:g id="ADDED_ITEMS">%2$s</xliff:g> 项)"</string>
+</resources>
diff --git a/v7/preference/res/values-zh-rHK/strings.xml b/v7/preference/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..fe64c50
--- /dev/null
+++ b/v7/preference/res/values-zh-rHK/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"開啟"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"關閉"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"進階"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>,<xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-zh-rTW/strings.xml b/v7/preference/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..fe64c50
--- /dev/null
+++ b/v7/preference/res/values-zh-rTW/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"開啟"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"關閉"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"進階"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>,<xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/v7/preference/res/values-zu/strings.xml b/v7/preference/res/values-zu/strings.xml
new file mode 100644
index 0000000..dab4cba
--- /dev/null
+++ b/v7/preference/res/values-zu/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="v7_preference_on" msgid="7922757586228621900">"VULA"</string>
+    <string name="v7_preference_off" msgid="2082379519172883894">"VALA"</string>
+    <string name="expand_button_title" msgid="3265458434114353660">"Okuthuthukisiwe"</string>
+    <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
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/AndroidManifest.xml b/v7/preference/src/main/AndroidManifest.xml
similarity index 100%
rename from v7/preference/AndroidManifest.xml
rename to v7/preference/src/main/AndroidManifest.xml
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/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/tests/src/android/support/v7/widget/AsyncListUtilLayoutTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/AsyncListUtilLayoutTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/AsyncListUtilLayoutTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/AsyncListUtilLayoutTest.java
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/AttachDetachCollector.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/AttachDetachCollector.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/AttachDetachCollector.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/AttachDetachCollector.java
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/tests/src/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/BaseStaggeredGridLayoutManagerTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/BaseStaggeredGridLayoutManagerTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/BaseStaggeredGridLayoutManagerTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/BaseStaggeredGridLayoutManagerTest.java
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/BaseWrapContentTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/BaseWrapContentTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/BaseWrapContentTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/BaseWrapContentTest.java
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/BaseWrapContentWithAspectRatioTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/BaseWrapContentWithAspectRatioTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/BaseWrapContentWithAspectRatioTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/BaseWrapContentWithAspectRatioTest.java
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/tests/src/android/support/v7/widget/CustomEdgeEffectTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/CustomEdgeEffectTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/CustomEdgeEffectTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/CustomEdgeEffectTest.java
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/DefaultItemAnimatorTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/DefaultItemAnimatorTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/DefaultItemAnimatorTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/DefaultItemAnimatorTest.java
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/tests/src/android/support/v7/widget/DividerItemDecorationTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/DividerItemDecorationTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/DividerItemDecorationTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/DividerItemDecorationTest.java
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/tests/src/android/support/v7/widget/FocusSearchNavigationTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/FocusSearchNavigationTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/FocusSearchNavigationTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/FocusSearchNavigationTest.java
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/tests/src/android/support/v7/widget/GridLayoutManagerCustomSizeInScrollDirectionTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/GridLayoutManagerCustomSizeInScrollDirectionTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerCustomSizeInScrollDirectionTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/GridLayoutManagerCustomSizeInScrollDirectionTest.java
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/tests/src/android/support/v7/widget/GridLayoutManagerRtlTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/GridLayoutManagerRtlTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerRtlTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/GridLayoutManagerRtlTest.java
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/tests/src/android/support/v7/widget/GridLayoutManagerTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/GridLayoutManagerTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/GridLayoutManagerTest.java
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/tests/src/android/support/v7/widget/ItemAnimatorV2ApiTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/ItemAnimatorV2ApiTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/ItemAnimatorV2ApiTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/ItemAnimatorV2ApiTest.java
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerBaseConfigSetTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/LinearLayoutManagerBaseConfigSetTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerBaseConfigSetTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/LinearLayoutManagerBaseConfigSetTest.java
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/tests/src/android/support/v7/widget/LinearLayoutManagerPrepareForDropTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/LinearLayoutManagerPrepareForDropTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerPrepareForDropTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/LinearLayoutManagerPrepareForDropTest.java
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/tests/src/android/support/v7/widget/LinearLayoutManagerTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/LinearLayoutManagerTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/LinearLayoutManagerTest.java
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/tests/src/android/support/v7/widget/MultiRecyclerViewPrefetchTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/MultiRecyclerViewPrefetchTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/MultiRecyclerViewPrefetchTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/MultiRecyclerViewPrefetchTest.java
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/tests/src/android/support/v7/widget/RecyclerViewAccessibilityLifecycleTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewAccessibilityLifecycleTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAccessibilityLifecycleTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewAccessibilityLifecycleTest.java
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/tests/src/android/support/v7/widget/RecyclerViewAnimationsTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewAnimationsTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAnimationsTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewAnimationsTest.java
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewBasicTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewBasicTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewBasicTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewBasicTest.java
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewCacheTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewCacheTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewCacheTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewCacheTest.java
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewFastScrollerTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewFastScrollerTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewFastScrollerTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewFastScrollerTest.java
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewFocusRecoveryTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewFocusRecoveryTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewFocusRecoveryTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewFocusRecoveryTest.java
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewLayoutTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewLayoutTest.java
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewOnGenericMotionEventTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewOnGenericMotionEventTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewOnGenericMotionEventTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewOnGenericMotionEventTest.java
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/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerBaseConfigSetTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/StaggeredGridLayoutManagerBaseConfigSetTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerBaseConfigSetTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/StaggeredGridLayoutManagerBaseConfigSetTest.java
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/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/StaggeredGridLayoutManagerTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/StaggeredGridLayoutManagerTest.java
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/tests/src/android/support/v7/widget/TestResizingRelayoutWithAutoMeasure.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/TestResizingRelayoutWithAutoMeasure.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/TestResizingRelayoutWithAutoMeasure.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/TestResizingRelayoutWithAutoMeasure.java
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/TestedFrameLayout.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/TestedFrameLayout.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/TestedFrameLayout.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/TestedFrameLayout.java
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/tests/src/android/support/v7/widget/WrapContentBasicTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/WrapContentBasicTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/WrapContentBasicTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/WrapContentBasicTest.java
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/tests/src/android/support/v7/widget/helper/ItemTouchHelperTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/helper/ItemTouchHelperTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/helper/ItemTouchHelperTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/helper/ItemTouchHelperTest.java
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/AndroidManifest.xml b/v7/recyclerview/src/main/AndroidManifest.xml
similarity index 100%
rename from v7/recyclerview/AndroidManifest.xml
rename to v7/recyclerview/src/main/AndroidManifest.xml
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/RecyclerView.java b/v7/recyclerview/src/main/java/android/support/v7/widget/RecyclerView.java
index 327e4cd..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;
@@ -588,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);
@@ -689,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;
     }
@@ -698,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);
     }
@@ -1067,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);
@@ -1083,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);
@@ -1120,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);
@@ -1149,6 +1151,7 @@
      * @return The previously set adapter
      * @see #setAdapter(Adapter)
      */
+    @Nullable
     public Adapter getAdapter() {
         return mAdapter;
     }
@@ -1163,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;
     }
 
@@ -1195,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<>();
         }
@@ -1207,7 +1211,8 @@
      *
      * @param listener Listener to unregister
      */
-    public void removeOnChildAttachStateChangeListener(OnChildAttachStateChangeListener listener) {
+    public void removeOnChildAttachStateChangeListener(
+            @NonNull OnChildAttachStateChangeListener listener) {
         if (mOnChildAttachStateListeners == null) {
             return;
         }
@@ -1236,7 +1241,7 @@
      *
      * @param layout LayoutManager to use
      */
-    public void setLayoutManager(LayoutManager layout) {
+    public void setLayoutManager(@Nullable LayoutManager layout) {
         if (layout == mLayout) {
             return;
         }
@@ -1394,6 +1399,7 @@
      *
      * @return The currently bound LayoutManager
      */
+    @Nullable
     public LayoutManager getLayoutManager() {
         return mLayout;
     }
@@ -1406,6 +1412,7 @@
      * @return The pool used to store recycled item views for reuse.
      * @see #setRecycledViewPool(RecycledViewPool)
      */
+    @NonNull
     public RecycledViewPool getRecycledViewPool() {
         return mRecycler.getRecycledViewPool();
     }
@@ -1418,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);
     }
 
@@ -1429,7 +1436,7 @@
      *
      * @see ViewCacheExtension#getViewForPositionAndType(Recycler, int, int)
      */
-    public void setViewCacheExtension(ViewCacheExtension extension) {
+    public void setViewCacheExtension(@Nullable ViewCacheExtension extension) {
         mRecycler.setViewCacheExtension(extension);
     }
 
@@ -1487,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");
@@ -1516,7 +1523,7 @@
      *
      * @param decor Decoration to add
      */
-    public void addItemDecoration(ItemDecoration decor) {
+    public void addItemDecoration(@NonNull ItemDecoration decor) {
         addItemDecoration(decor, -1);
     }
 
@@ -1524,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) {
@@ -1567,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");
@@ -1592,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;
         }
@@ -1609,7 +1619,7 @@
      *             {@link #removeOnScrollListener(OnScrollListener)}
      */
     @Deprecated
-    public void setOnScrollListener(OnScrollListener listener) {
+    public void setOnScrollListener(@Nullable OnScrollListener listener) {
         mScrollListener = listener;
     }
 
@@ -1620,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<>();
         }
@@ -1634,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);
         }
@@ -2151,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);
     }
 
@@ -2163,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.");
@@ -2462,6 +2472,7 @@
      * @return The previously set {@link EdgeEffectFactory}
      * @see #setEdgeEffectFactory(EdgeEffectFactory)
      */
+    @NonNull
     public EdgeEffectFactory getEdgeEffectFactory() {
         return mEdgeEffectFactory;
     }
@@ -2828,7 +2839,7 @@
      * @param listener Listener to add
      * @see SimpleOnItemTouchListener
      */
-    public void addOnItemTouchListener(OnItemTouchListener listener) {
+    public void addOnItemTouchListener(@NonNull OnItemTouchListener listener) {
         mOnItemTouchListeners.add(listener);
     }
 
@@ -2837,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;
@@ -3353,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);
@@ -3465,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;
     }
@@ -4547,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;
     }
@@ -4562,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;
     }
@@ -4573,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;
         }
@@ -4717,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--) {
@@ -4744,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);
@@ -4761,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) {
     }
 
     /**
@@ -4773,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) {
     }
 
     /**
@@ -4782,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);
@@ -4796,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);
     }
 
@@ -4854,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
     }
 
@@ -5281,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());
         }
@@ -5605,6 +5618,7 @@
          *
          * @return List of ViewHolders in the scrap list.
          */
+        @NonNull
         public List<ViewHolder> getScrapList() {
             return mUnmodifiableAttachedScrap;
         }
@@ -5656,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();
@@ -5691,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"
@@ -5766,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);
         }
@@ -6004,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);
@@ -6600,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);
     }
 
     /**
@@ -6701,6 +6718,7 @@
          *
          * @see #onCreateViewHolder(ViewGroup, int)
          */
+        @NonNull
         public final VH createViewHolder(@NonNull ViewGroup parent, int viewType) {
             try {
                 TraceCompat.beginSection(TRACE_CREATE_VIEW_TAG);
@@ -10492,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
@@ -10505,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){}
     }
 
     /**
@@ -10706,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");
             }
@@ -11623,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
@@ -11663,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);
             }
 
@@ -11672,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);
             }
 
@@ -11683,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;
@@ -11755,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;
             }
@@ -11782,6 +11804,7 @@
                 mDuration = duration;
             }
 
+            @Nullable
             public Interpolator getInterpolator() {
                 return mInterpolator;
             }
@@ -11792,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;
             }
@@ -11805,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/StaggeredGridLayoutManager.java b/v7/recyclerview/src/main/java/android/support/v7/widget/StaggeredGridLayoutManager.java
index 89462f1..de0d6aa 100644
--- a/v7/recyclerview/src/main/java/android/support/v7/widget/StaggeredGridLayoutManager.java
+++ b/v7/recyclerview/src/main/java/android/support/v7/widget/StaggeredGridLayoutManager.java
@@ -324,6 +324,8 @@
 
     @Override
     public void onDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) {
+        super.onDetachedFromWindow(view, recycler);
+
         removeCallbacks(mCheckForGapsRunnable);
         for (int i = 0; i < mSpanCount; i++) {
             mSpans[i].clear();
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/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/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..7af8029
--- /dev/null
+++ b/viewpager/src/androidTest/java/android/support/v4/view/BaseViewPagerTest.java
@@ -0,0 +1,1112 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.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.test.rule.ActivityTestRule;
+import android.support.v4.testutils.TestUtilsMatchers;
+import android.support.viewpager.test.R;
+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.Rule;
+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> {
+    @Rule
+    public final ActivityTestRule<T> mActivityTestRule;
+
+    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) {
+        mActivityTestRule = new ActivityTestRule<T>(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/viewpager/src/main/java/android/support/v4/view/ViewPager.java b/viewpager/src/main/java/android/support/v4/view/ViewPager.java
new file mode 100644
index 0000000..b0d469e
--- /dev/null
+++ b/viewpager/src/main/java/android/support/v4/view/ViewPager.java
@@ -0,0 +1,3163 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.view;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.database.DataSetObserver;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.SystemClock;
+import android.support.annotation.CallSuper;
+import android.support.annotation.DrawableRes;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.Px;
+import android.support.v4.content.ContextCompat;
+import android.support.v4.view.accessibility.AccessibilityEventCompat;
+import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.FocusFinder;
+import android.view.Gravity;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.SoundEffectConstants;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.animation.Interpolator;
+import android.widget.EdgeEffect;
+import android.widget.Scroller;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * Layout manager that allows the user to flip left and right
+ * through pages of data.  You supply an implementation of a
+ * {@link PagerAdapter} to generate the pages that the view shows.
+ *
+ * <p>ViewPager is most often used in conjunction with {@link android.app.Fragment},
+ * which is a convenient way to supply and manage the lifecycle of each page.
+ * There are standard adapters implemented for using fragments with the ViewPager,
+ * which cover the most common use cases.  These are
+ * {@link android.support.v4.app.FragmentPagerAdapter} and
+ * {@link android.support.v4.app.FragmentStatePagerAdapter}; each of these
+ * classes have simple code showing how to build a full user interface
+ * with them.
+ *
+ * <p>Views which are annotated with the {@link DecorView} annotation are treated as
+ * part of the view pagers 'decor'. Each decor view's position can be controlled via
+ * its {@code android:layout_gravity} attribute. For example:
+ *
+ * <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.v4.view.PagerTitleStrip
+ *         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>
+ *
+ * <p>For more information about how to use ViewPager, read <a
+ * href="{@docRoot}training/implementing-navigation/lateral.html">Creating Swipe Views with
+ * Tabs</a>.</p>
+ *
+ * <p>You can find examples of using ViewPager in the API 4+ Support Demos and API 13+ Support Demos
+ * sample code.
+ */
+public class ViewPager extends ViewGroup {
+    private static final String TAG = "ViewPager";
+    private static final boolean DEBUG = false;
+
+    private static final boolean USE_CACHE = false;
+
+    private static final int DEFAULT_OFFSCREEN_PAGES = 1;
+    private static final int MAX_SETTLE_DURATION = 600; // ms
+    private static final int MIN_DISTANCE_FOR_FLING = 25; // dips
+
+    private static final int DEFAULT_GUTTER_SIZE = 16; // dips
+
+    private static final int MIN_FLING_VELOCITY = 400; // dips
+
+    static final int[] LAYOUT_ATTRS = new int[] {
+        android.R.attr.layout_gravity
+    };
+
+    /**
+     * Used to track what the expected number of items in the adapter should be.
+     * If the app changes this when we don't expect it, we'll throw a big obnoxious exception.
+     */
+    private int mExpectedAdapterCount;
+
+    static class ItemInfo {
+        Object object;
+        int position;
+        boolean scrolling;
+        float widthFactor;
+        float offset;
+    }
+
+    private static final Comparator<ItemInfo> COMPARATOR = new Comparator<ItemInfo>(){
+        @Override
+        public int compare(ItemInfo lhs, ItemInfo rhs) {
+            return lhs.position - rhs.position;
+        }
+    };
+
+    private static final Interpolator sInterpolator = new Interpolator() {
+        @Override
+        public float getInterpolation(float t) {
+            t -= 1.0f;
+            return t * t * t * t * t + 1.0f;
+        }
+    };
+
+    private final ArrayList<ItemInfo> mItems = new ArrayList<ItemInfo>();
+    private final ItemInfo mTempItem = new ItemInfo();
+
+    private final Rect mTempRect = new Rect();
+
+    PagerAdapter mAdapter;
+    int mCurItem;   // Index of currently displayed page.
+    private int mRestoredCurItem = -1;
+    private Parcelable mRestoredAdapterState = null;
+    private ClassLoader mRestoredClassLoader = null;
+
+    private Scroller mScroller;
+    private boolean mIsScrollStarted;
+
+    private PagerObserver mObserver;
+
+    private int mPageMargin;
+    private Drawable mMarginDrawable;
+    private int mTopPageBounds;
+    private int mBottomPageBounds;
+
+    // Offsets of the first and last items, if known.
+    // Set during population, used to determine if we are at the beginning
+    // or end of the pager data set during touch scrolling.
+    private float mFirstOffset = -Float.MAX_VALUE;
+    private float mLastOffset = Float.MAX_VALUE;
+
+    private int mChildWidthMeasureSpec;
+    private int mChildHeightMeasureSpec;
+    private boolean mInLayout;
+
+    private boolean mScrollingCacheEnabled;
+
+    private boolean mPopulatePending;
+    private int mOffscreenPageLimit = DEFAULT_OFFSCREEN_PAGES;
+
+    private boolean mIsBeingDragged;
+    private boolean mIsUnableToDrag;
+    private int mDefaultGutterSize;
+    private int mGutterSize;
+    private int mTouchSlop;
+    /**
+     * Position of the last motion event.
+     */
+    private float mLastMotionX;
+    private float mLastMotionY;
+    private float mInitialMotionX;
+    private float mInitialMotionY;
+    /**
+     * ID of the active pointer. This is used to retain consistency during
+     * drags/flings if multiple pointers are used.
+     */
+    private int mActivePointerId = INVALID_POINTER;
+    /**
+     * Sentinel value for no current active pointer.
+     * Used by {@link #mActivePointerId}.
+     */
+    private static final int INVALID_POINTER = -1;
+
+    /**
+     * Determines speed during touch scrolling
+     */
+    private VelocityTracker mVelocityTracker;
+    private int mMinimumVelocity;
+    private int mMaximumVelocity;
+    private int mFlingDistance;
+    private int mCloseEnough;
+
+    // If the pager is at least this close to its final position, complete the scroll
+    // on touch down and let the user interact with the content inside instead of
+    // "catching" the flinging pager.
+    private static final int CLOSE_ENOUGH = 2; // dp
+
+    private boolean mFakeDragging;
+    private long mFakeDragBeginTime;
+
+    private EdgeEffect mLeftEdge;
+    private EdgeEffect mRightEdge;
+
+    private boolean mFirstLayout = true;
+    private boolean mNeedCalculatePageOffsets = false;
+    private boolean mCalledSuper;
+    private int mDecorChildCount;
+
+    private List<OnPageChangeListener> mOnPageChangeListeners;
+    private OnPageChangeListener mOnPageChangeListener;
+    private OnPageChangeListener mInternalPageChangeListener;
+    private List<OnAdapterChangeListener> mAdapterChangeListeners;
+    private PageTransformer mPageTransformer;
+    private int mPageTransformerLayerType;
+
+    private static final int DRAW_ORDER_DEFAULT = 0;
+    private static final int DRAW_ORDER_FORWARD = 1;
+    private static final int DRAW_ORDER_REVERSE = 2;
+    private int mDrawingOrder;
+    private ArrayList<View> mDrawingOrderedChildren;
+    private static final ViewPositionComparator sPositionComparator = new ViewPositionComparator();
+
+    /**
+     * Indicates that the pager is in an idle, settled state. The current page
+     * is fully in view and no animation is in progress.
+     */
+    public static final int SCROLL_STATE_IDLE = 0;
+
+    /**
+     * Indicates that the pager is currently being dragged by the user.
+     */
+    public static final int SCROLL_STATE_DRAGGING = 1;
+
+    /**
+     * Indicates that the pager is in the process of settling to a final position.
+     */
+    public static final int SCROLL_STATE_SETTLING = 2;
+
+    private final Runnable mEndScrollRunnable = new Runnable() {
+        @Override
+        public void run() {
+            setScrollState(SCROLL_STATE_IDLE);
+            populate();
+        }
+    };
+
+    private int mScrollState = SCROLL_STATE_IDLE;
+
+    /**
+     * Callback interface for responding to changing state of the selected page.
+     */
+    public interface OnPageChangeListener {
+
+        /**
+         * This method will be invoked when the current page is scrolled, either as part
+         * of a programmatically initiated smooth scroll or a user initiated touch scroll.
+         *
+         * @param position Position index of the first page currently being displayed.
+         *                 Page position+1 will be visible if positionOffset is nonzero.
+         * @param positionOffset Value from [0, 1) indicating the offset from the page at position.
+         * @param positionOffsetPixels Value in pixels indicating the offset from position.
+         */
+        void onPageScrolled(int position, float positionOffset, @Px int positionOffsetPixels);
+
+        /**
+         * This method will be invoked when a new page becomes selected. Animation is not
+         * necessarily complete.
+         *
+         * @param position Position index of the new selected page.
+         */
+        void onPageSelected(int position);
+
+        /**
+         * Called when the scroll state changes. Useful for discovering when the user
+         * begins dragging, when the pager is automatically settling to the current page,
+         * or when it is fully stopped/idle.
+         *
+         * @param state The new scroll state.
+         * @see ViewPager#SCROLL_STATE_IDLE
+         * @see ViewPager#SCROLL_STATE_DRAGGING
+         * @see ViewPager#SCROLL_STATE_SETTLING
+         */
+        void onPageScrollStateChanged(int state);
+    }
+
+    /**
+     * Simple implementation of the {@link OnPageChangeListener} interface with stub
+     * implementations of each method. Extend this if you do not intend to override
+     * every method of {@link OnPageChangeListener}.
+     */
+    public static class SimpleOnPageChangeListener implements OnPageChangeListener {
+        @Override
+        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+            // This space for rent
+        }
+
+        @Override
+        public void onPageSelected(int position) {
+            // This space for rent
+        }
+
+        @Override
+        public void onPageScrollStateChanged(int state) {
+            // This space for rent
+        }
+    }
+
+    /**
+     * A PageTransformer is invoked whenever a visible/attached page is scrolled.
+     * This offers an opportunity for the application to apply a custom transformation
+     * to the page views using animation properties.
+     *
+     * <p>As property animation is only supported as of Android 3.0 and forward,
+     * setting a PageTransformer on a ViewPager on earlier platform versions will
+     * be ignored.</p>
+     */
+    public interface PageTransformer {
+        /**
+         * Apply a property transformation to the given page.
+         *
+         * @param page Apply the transformation to this page
+         * @param position Position of page relative to the current front-and-center
+         *                 position of the pager. 0 is front and center. 1 is one full
+         *                 page position to the right, and -1 is one page position to the left.
+         */
+        void transformPage(@NonNull View page, float position);
+    }
+
+    /**
+     * Callback interface for responding to adapter changes.
+     */
+    public interface OnAdapterChangeListener {
+        /**
+         * Called when the adapter for the given view pager has changed.
+         *
+         * @param viewPager  ViewPager where the adapter change has happened
+         * @param oldAdapter the previously set adapter
+         * @param newAdapter the newly set adapter
+         */
+        void onAdapterChanged(@NonNull ViewPager viewPager,
+                @Nullable PagerAdapter oldAdapter, @Nullable PagerAdapter newAdapter);
+    }
+
+    /**
+     * Annotation which allows marking of views to be decoration views when added to a view
+     * pager.
+     *
+     * <p>Views marked with this annotation can be added to the view pager with a layout resource.
+     * An example being {@link PagerTitleStrip}.</p>
+     *
+     * <p>You can also control whether a view is a decor view but setting
+     * {@link LayoutParams#isDecor} on the child's layout params.</p>
+     */
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.TYPE)
+    @Inherited
+    public @interface DecorView {
+    }
+
+    public ViewPager(@NonNull Context context) {
+        super(context);
+        initViewPager();
+    }
+
+    public ViewPager(@NonNull Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+        initViewPager();
+    }
+
+    void initViewPager() {
+        setWillNotDraw(false);
+        setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
+        setFocusable(true);
+        final Context context = getContext();
+        mScroller = new Scroller(context, sInterpolator);
+        final ViewConfiguration configuration = ViewConfiguration.get(context);
+        final float density = context.getResources().getDisplayMetrics().density;
+
+        mTouchSlop = configuration.getScaledPagingTouchSlop();
+        mMinimumVelocity = (int) (MIN_FLING_VELOCITY * density);
+        mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
+        mLeftEdge = new EdgeEffect(context);
+        mRightEdge = new EdgeEffect(context);
+
+        mFlingDistance = (int) (MIN_DISTANCE_FOR_FLING * density);
+        mCloseEnough = (int) (CLOSE_ENOUGH * density);
+        mDefaultGutterSize = (int) (DEFAULT_GUTTER_SIZE * density);
+
+        ViewCompat.setAccessibilityDelegate(this, new MyAccessibilityDelegate());
+
+        if (ViewCompat.getImportantForAccessibility(this)
+                == ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
+            ViewCompat.setImportantForAccessibility(this,
+                    ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
+        }
+
+        ViewCompat.setOnApplyWindowInsetsListener(this,
+                new android.support.v4.view.OnApplyWindowInsetsListener() {
+                    private final Rect mTempRect = new Rect();
+
+                    @Override
+                    public WindowInsetsCompat onApplyWindowInsets(final View v,
+                            final WindowInsetsCompat originalInsets) {
+                        // First let the ViewPager itself try and consume them...
+                        final WindowInsetsCompat applied =
+                                ViewCompat.onApplyWindowInsets(v, originalInsets);
+                        if (applied.isConsumed()) {
+                            // If the ViewPager consumed all insets, return now
+                            return applied;
+                        }
+
+                        // Now we'll manually dispatch the insets to our children. Since ViewPager
+                        // children are always full-height, we do not want to use the standard
+                        // ViewGroup dispatchApplyWindowInsets since if child 0 consumes them,
+                        // the rest of the children will not receive any insets. To workaround this
+                        // we manually dispatch the applied insets, not allowing children to
+                        // consume them from each other. We do however keep track of any insets
+                        // which are consumed, returning the union of our children's consumption
+                        final Rect res = mTempRect;
+                        res.left = applied.getSystemWindowInsetLeft();
+                        res.top = applied.getSystemWindowInsetTop();
+                        res.right = applied.getSystemWindowInsetRight();
+                        res.bottom = applied.getSystemWindowInsetBottom();
+
+                        for (int i = 0, count = getChildCount(); i < count; i++) {
+                            final WindowInsetsCompat childInsets = ViewCompat
+                                    .dispatchApplyWindowInsets(getChildAt(i), applied);
+                            // Now keep track of any consumed by tracking each dimension's min
+                            // value
+                            res.left = Math.min(childInsets.getSystemWindowInsetLeft(),
+                                    res.left);
+                            res.top = Math.min(childInsets.getSystemWindowInsetTop(),
+                                    res.top);
+                            res.right = Math.min(childInsets.getSystemWindowInsetRight(),
+                                    res.right);
+                            res.bottom = Math.min(childInsets.getSystemWindowInsetBottom(),
+                                    res.bottom);
+                        }
+
+                        // Now return a new WindowInsets, using the consumed window insets
+                        return applied.replaceSystemWindowInsets(
+                                res.left, res.top, res.right, res.bottom);
+                    }
+                });
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        removeCallbacks(mEndScrollRunnable);
+        // To be on the safe side, abort the scroller
+        if ((mScroller != null) && !mScroller.isFinished()) {
+            mScroller.abortAnimation();
+        }
+        super.onDetachedFromWindow();
+    }
+
+    void setScrollState(int newState) {
+        if (mScrollState == newState) {
+            return;
+        }
+
+        mScrollState = newState;
+        if (mPageTransformer != null) {
+            // PageTransformers can do complex things that benefit from hardware layers.
+            enableLayers(newState != SCROLL_STATE_IDLE);
+        }
+        dispatchOnScrollStateChanged(newState);
+    }
+
+    /**
+     * Set a PagerAdapter that will supply views for this pager as needed.
+     *
+     * @param adapter Adapter to use
+     */
+    public void setAdapter(@Nullable PagerAdapter adapter) {
+        if (mAdapter != null) {
+            mAdapter.setViewPagerObserver(null);
+            mAdapter.startUpdate(this);
+            for (int i = 0; i < mItems.size(); i++) {
+                final ItemInfo ii = mItems.get(i);
+                mAdapter.destroyItem(this, ii.position, ii.object);
+            }
+            mAdapter.finishUpdate(this);
+            mItems.clear();
+            removeNonDecorViews();
+            mCurItem = 0;
+            scrollTo(0, 0);
+        }
+
+        final PagerAdapter oldAdapter = mAdapter;
+        mAdapter = adapter;
+        mExpectedAdapterCount = 0;
+
+        if (mAdapter != null) {
+            if (mObserver == null) {
+                mObserver = new PagerObserver();
+            }
+            mAdapter.setViewPagerObserver(mObserver);
+            mPopulatePending = false;
+            final boolean wasFirstLayout = mFirstLayout;
+            mFirstLayout = true;
+            mExpectedAdapterCount = mAdapter.getCount();
+            if (mRestoredCurItem >= 0) {
+                mAdapter.restoreState(mRestoredAdapterState, mRestoredClassLoader);
+                setCurrentItemInternal(mRestoredCurItem, false, true);
+                mRestoredCurItem = -1;
+                mRestoredAdapterState = null;
+                mRestoredClassLoader = null;
+            } else if (!wasFirstLayout) {
+                populate();
+            } else {
+                requestLayout();
+            }
+        }
+
+        // Dispatch the change to any listeners
+        if (mAdapterChangeListeners != null && !mAdapterChangeListeners.isEmpty()) {
+            for (int i = 0, count = mAdapterChangeListeners.size(); i < count; i++) {
+                mAdapterChangeListeners.get(i).onAdapterChanged(this, oldAdapter, adapter);
+            }
+        }
+    }
+
+    private void removeNonDecorViews() {
+        for (int i = 0; i < getChildCount(); i++) {
+            final View child = getChildAt(i);
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+            if (!lp.isDecor) {
+                removeViewAt(i);
+                i--;
+            }
+        }
+    }
+
+    /**
+     * Retrieve the current adapter supplying pages.
+     *
+     * @return The currently registered PagerAdapter
+     */
+    @Nullable
+    public PagerAdapter getAdapter() {
+        return mAdapter;
+    }
+
+    /**
+     * Add a listener that will be invoked whenever the adapter for this ViewPager changes.
+     *
+     * @param listener listener to add
+     */
+    public void addOnAdapterChangeListener(@NonNull OnAdapterChangeListener listener) {
+        if (mAdapterChangeListeners == null) {
+            mAdapterChangeListeners = new ArrayList<>();
+        }
+        mAdapterChangeListeners.add(listener);
+    }
+
+    /**
+     * Remove a listener that was previously added via
+     * {@link #addOnAdapterChangeListener(OnAdapterChangeListener)}.
+     *
+     * @param listener listener to remove
+     */
+    public void removeOnAdapterChangeListener(@NonNull OnAdapterChangeListener listener) {
+        if (mAdapterChangeListeners != null) {
+            mAdapterChangeListeners.remove(listener);
+        }
+    }
+
+    private int getClientWidth() {
+        return getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
+    }
+
+    /**
+     * Set the currently selected page. If the ViewPager has already been through its first
+     * layout with its current adapter there will be a smooth animated transition between
+     * the current item and the specified item.
+     *
+     * @param item Item index to select
+     */
+    public void setCurrentItem(int item) {
+        mPopulatePending = false;
+        setCurrentItemInternal(item, !mFirstLayout, false);
+    }
+
+    /**
+     * Set the currently selected page.
+     *
+     * @param item Item index to select
+     * @param smoothScroll True to smoothly scroll to the new item, false to transition immediately
+     */
+    public void setCurrentItem(int item, boolean smoothScroll) {
+        mPopulatePending = false;
+        setCurrentItemInternal(item, smoothScroll, false);
+    }
+
+    public int getCurrentItem() {
+        return mCurItem;
+    }
+
+    void setCurrentItemInternal(int item, boolean smoothScroll, boolean always) {
+        setCurrentItemInternal(item, smoothScroll, always, 0);
+    }
+
+    void setCurrentItemInternal(int item, boolean smoothScroll, boolean always, int velocity) {
+        if (mAdapter == null || mAdapter.getCount() <= 0) {
+            setScrollingCacheEnabled(false);
+            return;
+        }
+        if (!always && mCurItem == item && mItems.size() != 0) {
+            setScrollingCacheEnabled(false);
+            return;
+        }
+
+        if (item < 0) {
+            item = 0;
+        } else if (item >= mAdapter.getCount()) {
+            item = mAdapter.getCount() - 1;
+        }
+        final int pageLimit = mOffscreenPageLimit;
+        if (item > (mCurItem + pageLimit) || item < (mCurItem - pageLimit)) {
+            // We are doing a jump by more than one page.  To avoid
+            // glitches, we want to keep all current pages in the view
+            // until the scroll ends.
+            for (int i = 0; i < mItems.size(); i++) {
+                mItems.get(i).scrolling = true;
+            }
+        }
+        final boolean dispatchSelected = mCurItem != item;
+
+        if (mFirstLayout) {
+            // We don't have any idea how big we are yet and shouldn't have any pages either.
+            // Just set things up and let the pending layout handle things.
+            mCurItem = item;
+            if (dispatchSelected) {
+                dispatchOnPageSelected(item);
+            }
+            requestLayout();
+        } else {
+            populate(item);
+            scrollToItem(item, smoothScroll, velocity, dispatchSelected);
+        }
+    }
+
+    private void scrollToItem(int item, boolean smoothScroll, int velocity,
+            boolean dispatchSelected) {
+        final ItemInfo curInfo = infoForPosition(item);
+        int destX = 0;
+        if (curInfo != null) {
+            final int width = getClientWidth();
+            destX = (int) (width * Math.max(mFirstOffset,
+                    Math.min(curInfo.offset, mLastOffset)));
+        }
+        if (smoothScroll) {
+            smoothScrollTo(destX, 0, velocity);
+            if (dispatchSelected) {
+                dispatchOnPageSelected(item);
+            }
+        } else {
+            if (dispatchSelected) {
+                dispatchOnPageSelected(item);
+            }
+            completeScroll(false);
+            scrollTo(destX, 0);
+            pageScrolled(destX);
+        }
+    }
+
+    /**
+     * Set a listener that will be invoked whenever the page changes or is incrementally
+     * scrolled. See {@link OnPageChangeListener}.
+     *
+     * @param listener Listener to set
+     *
+     * @deprecated Use {@link #addOnPageChangeListener(OnPageChangeListener)}
+     * and {@link #removeOnPageChangeListener(OnPageChangeListener)} instead.
+     */
+    @Deprecated
+    public void setOnPageChangeListener(OnPageChangeListener listener) {
+        mOnPageChangeListener = listener;
+    }
+
+    /**
+     * Add a listener that will be invoked whenever the page changes or is incrementally
+     * scrolled. See {@link OnPageChangeListener}.
+     *
+     * <p>Components that add a listener should take care to remove it when finished.
+     * Other components that take ownership of a view may call {@link #clearOnPageChangeListeners()}
+     * to remove all attached listeners.</p>
+     *
+     * @param listener listener to add
+     */
+    public void addOnPageChangeListener(@NonNull OnPageChangeListener listener) {
+        if (mOnPageChangeListeners == null) {
+            mOnPageChangeListeners = new ArrayList<>();
+        }
+        mOnPageChangeListeners.add(listener);
+    }
+
+    /**
+     * Remove a listener that was previously added via
+     * {@link #addOnPageChangeListener(OnPageChangeListener)}.
+     *
+     * @param listener listener to remove
+     */
+    public void removeOnPageChangeListener(@NonNull OnPageChangeListener listener) {
+        if (mOnPageChangeListeners != null) {
+            mOnPageChangeListeners.remove(listener);
+        }
+    }
+
+    /**
+     * Remove all listeners that are notified of any changes in scroll state or position.
+     */
+    public void clearOnPageChangeListeners() {
+        if (mOnPageChangeListeners != null) {
+            mOnPageChangeListeners.clear();
+        }
+    }
+
+    /**
+     * Sets a {@link PageTransformer} that will be called for each attached page whenever
+     * the scroll position is changed. This allows the application to apply custom property
+     * transformations to each page, overriding the default sliding behavior.
+     *
+     * <p><em>Note:</em> By default, calling this method will cause contained pages to use
+     * {@link View#LAYER_TYPE_HARDWARE}. This layer type allows custom alpha transformations,
+     * but it will cause issues if any of your pages contain a {@link android.view.SurfaceView}
+     * and you have not called {@link android.view.SurfaceView#setZOrderOnTop(boolean)} to put that
+     * {@link android.view.SurfaceView} above your app content. To disable this behavior, call
+     * {@link #setPageTransformer(boolean,PageTransformer,int)} and pass
+     * {@link View#LAYER_TYPE_NONE} for {@code pageLayerType}.</p>
+     *
+     * @param reverseDrawingOrder true if the supplied PageTransformer requires page views
+     *                            to be drawn from last to first instead of first to last.
+     * @param transformer PageTransformer that will modify each page's animation properties
+     */
+    public void setPageTransformer(boolean reverseDrawingOrder,
+            @Nullable PageTransformer transformer) {
+        setPageTransformer(reverseDrawingOrder, transformer, View.LAYER_TYPE_HARDWARE);
+    }
+
+    /**
+     * Sets a {@link PageTransformer} that will be called for each attached page whenever
+     * the scroll position is changed. This allows the application to apply custom property
+     * transformations to each page, overriding the default sliding behavior.
+     *
+     * @param reverseDrawingOrder true if the supplied PageTransformer requires page views
+     *                            to be drawn from last to first instead of first to last.
+     * @param transformer PageTransformer that will modify each page's animation properties
+     * @param pageLayerType View layer type that should be used for ViewPager pages. It should be
+     *                      either {@link View#LAYER_TYPE_HARDWARE},
+     *                      {@link View#LAYER_TYPE_SOFTWARE}, or
+     *                      {@link View#LAYER_TYPE_NONE}.
+     */
+    public void setPageTransformer(boolean reverseDrawingOrder,
+            @Nullable PageTransformer transformer, int pageLayerType) {
+        final boolean hasTransformer = transformer != null;
+        final boolean needsPopulate = hasTransformer != (mPageTransformer != null);
+        mPageTransformer = transformer;
+        setChildrenDrawingOrderEnabled(hasTransformer);
+        if (hasTransformer) {
+            mDrawingOrder = reverseDrawingOrder ? DRAW_ORDER_REVERSE : DRAW_ORDER_FORWARD;
+            mPageTransformerLayerType = pageLayerType;
+        } else {
+            mDrawingOrder = DRAW_ORDER_DEFAULT;
+        }
+        if (needsPopulate) populate();
+    }
+
+    @Override
+    protected int getChildDrawingOrder(int childCount, int i) {
+        final int index = mDrawingOrder == DRAW_ORDER_REVERSE ? childCount - 1 - i : i;
+        final int result =
+                ((LayoutParams) mDrawingOrderedChildren.get(index).getLayoutParams()).childIndex;
+        return result;
+    }
+
+    /**
+     * Set a separate OnPageChangeListener for internal use by the support library.
+     *
+     * @param listener Listener to set
+     * @return The old listener that was set, if any.
+     */
+    OnPageChangeListener setInternalPageChangeListener(OnPageChangeListener listener) {
+        OnPageChangeListener oldListener = mInternalPageChangeListener;
+        mInternalPageChangeListener = listener;
+        return oldListener;
+    }
+
+    /**
+     * Returns the number of pages that will be retained to either side of the
+     * current page in the view hierarchy in an idle state. Defaults to 1.
+     *
+     * @return How many pages will be kept offscreen on either side
+     * @see #setOffscreenPageLimit(int)
+     */
+    public int getOffscreenPageLimit() {
+        return mOffscreenPageLimit;
+    }
+
+    /**
+     * Set the number of pages that should be retained to either side of the
+     * current page in the view hierarchy in an idle state. Pages beyond this
+     * limit will be recreated from the adapter when needed.
+     *
+     * <p>This is offered as an optimization. If you know in advance the number
+     * of pages you will need to support or have lazy-loading mechanisms in place
+     * on your pages, tweaking this setting can have benefits in perceived smoothness
+     * of paging animations and interaction. If you have a small number of pages (3-4)
+     * that you can keep active all at once, less time will be spent in layout for
+     * newly created view subtrees as the user pages back and forth.</p>
+     *
+     * <p>You should keep this limit low, especially if your pages have complex layouts.
+     * This setting defaults to 1.</p>
+     *
+     * @param limit How many pages will be kept offscreen in an idle state.
+     */
+    public void setOffscreenPageLimit(int limit) {
+        if (limit < DEFAULT_OFFSCREEN_PAGES) {
+            Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to "
+                    + DEFAULT_OFFSCREEN_PAGES);
+            limit = DEFAULT_OFFSCREEN_PAGES;
+        }
+        if (limit != mOffscreenPageLimit) {
+            mOffscreenPageLimit = limit;
+            populate();
+        }
+    }
+
+    /**
+     * Set the margin between pages.
+     *
+     * @param marginPixels Distance between adjacent pages in pixels
+     * @see #getPageMargin()
+     * @see #setPageMarginDrawable(Drawable)
+     * @see #setPageMarginDrawable(int)
+     */
+    public void setPageMargin(int marginPixels) {
+        final int oldMargin = mPageMargin;
+        mPageMargin = marginPixels;
+
+        final int width = getWidth();
+        recomputeScrollPosition(width, width, marginPixels, oldMargin);
+
+        requestLayout();
+    }
+
+    /**
+     * Return the margin between pages.
+     *
+     * @return The size of the margin in pixels
+     */
+    public int getPageMargin() {
+        return mPageMargin;
+    }
+
+    /**
+     * Set a drawable that will be used to fill the margin between pages.
+     *
+     * @param d Drawable to display between pages
+     */
+    public void setPageMarginDrawable(@Nullable Drawable d) {
+        mMarginDrawable = d;
+        if (d != null) refreshDrawableState();
+        setWillNotDraw(d == null);
+        invalidate();
+    }
+
+    /**
+     * Set a drawable that will be used to fill the margin between pages.
+     *
+     * @param resId Resource ID of a drawable to display between pages
+     */
+    public void setPageMarginDrawable(@DrawableRes int resId) {
+        setPageMarginDrawable(ContextCompat.getDrawable(getContext(), resId));
+    }
+
+    @Override
+    protected boolean verifyDrawable(Drawable who) {
+        return super.verifyDrawable(who) || who == mMarginDrawable;
+    }
+
+    @Override
+    protected void drawableStateChanged() {
+        super.drawableStateChanged();
+        final Drawable d = mMarginDrawable;
+        if (d != null && d.isStateful()) {
+            d.setState(getDrawableState());
+        }
+    }
+
+    // We want the duration of the page snap animation to be influenced by the distance that
+    // the screen has to travel, however, we don't want this duration to be effected in a
+    // purely linear fashion. Instead, we use this method to moderate the effect that the distance
+    // of travel has on the overall snap duration.
+    float distanceInfluenceForSnapDuration(float f) {
+        f -= 0.5f; // center the values about 0.
+        f *= 0.3f * (float) Math.PI / 2.0f;
+        return (float) Math.sin(f);
+    }
+
+    /**
+     * Like {@link View#scrollBy}, but scroll smoothly instead of immediately.
+     *
+     * @param x the number of pixels to scroll by on the X axis
+     * @param y the number of pixels to scroll by on the Y axis
+     */
+    void smoothScrollTo(int x, int y) {
+        smoothScrollTo(x, y, 0);
+    }
+
+    /**
+     * Like {@link View#scrollBy}, but scroll smoothly instead of immediately.
+     *
+     * @param x the number of pixels to scroll by on the X axis
+     * @param y the number of pixels to scroll by on the Y axis
+     * @param velocity the velocity associated with a fling, if applicable. (0 otherwise)
+     */
+    void smoothScrollTo(int x, int y, int velocity) {
+        if (getChildCount() == 0) {
+            // Nothing to do.
+            setScrollingCacheEnabled(false);
+            return;
+        }
+
+        int sx;
+        boolean wasScrolling = (mScroller != null) && !mScroller.isFinished();
+        if (wasScrolling) {
+            // We're in the middle of a previously initiated scrolling. Check to see
+            // whether that scrolling has actually started (if we always call getStartX
+            // we can get a stale value from the scroller if it hadn't yet had its first
+            // computeScrollOffset call) to decide what is the current scrolling position.
+            sx = mIsScrollStarted ? mScroller.getCurrX() : mScroller.getStartX();
+            // And abort the current scrolling.
+            mScroller.abortAnimation();
+            setScrollingCacheEnabled(false);
+        } else {
+            sx = getScrollX();
+        }
+        int sy = getScrollY();
+        int dx = x - sx;
+        int dy = y - sy;
+        if (dx == 0 && dy == 0) {
+            completeScroll(false);
+            populate();
+            setScrollState(SCROLL_STATE_IDLE);
+            return;
+        }
+
+        setScrollingCacheEnabled(true);
+        setScrollState(SCROLL_STATE_SETTLING);
+
+        final int width = getClientWidth();
+        final int halfWidth = width / 2;
+        final float distanceRatio = Math.min(1f, 1.0f * Math.abs(dx) / width);
+        final float distance = halfWidth + halfWidth
+                * distanceInfluenceForSnapDuration(distanceRatio);
+
+        int duration;
+        velocity = Math.abs(velocity);
+        if (velocity > 0) {
+            duration = 4 * Math.round(1000 * Math.abs(distance / velocity));
+        } else {
+            final float pageWidth = width * mAdapter.getPageWidth(mCurItem);
+            final float pageDelta = (float) Math.abs(dx) / (pageWidth + mPageMargin);
+            duration = (int) ((pageDelta + 1) * 100);
+        }
+        duration = Math.min(duration, MAX_SETTLE_DURATION);
+
+        // Reset the "scroll started" flag. It will be flipped to true in all places
+        // where we call computeScrollOffset().
+        mIsScrollStarted = false;
+        mScroller.startScroll(sx, sy, dx, dy, duration);
+        ViewCompat.postInvalidateOnAnimation(this);
+    }
+
+    ItemInfo addNewItem(int position, int index) {
+        ItemInfo ii = new ItemInfo();
+        ii.position = position;
+        ii.object = mAdapter.instantiateItem(this, position);
+        ii.widthFactor = mAdapter.getPageWidth(position);
+        if (index < 0 || index >= mItems.size()) {
+            mItems.add(ii);
+        } else {
+            mItems.add(index, ii);
+        }
+        return ii;
+    }
+
+    void dataSetChanged() {
+        // This method only gets called if our observer is attached, so mAdapter is non-null.
+
+        final int adapterCount = mAdapter.getCount();
+        mExpectedAdapterCount = adapterCount;
+        boolean needPopulate = mItems.size() < mOffscreenPageLimit * 2 + 1
+                && mItems.size() < adapterCount;
+        int newCurrItem = mCurItem;
+
+        boolean isUpdating = false;
+        for (int i = 0; i < mItems.size(); i++) {
+            final ItemInfo ii = mItems.get(i);
+            final int newPos = mAdapter.getItemPosition(ii.object);
+
+            if (newPos == PagerAdapter.POSITION_UNCHANGED) {
+                continue;
+            }
+
+            if (newPos == PagerAdapter.POSITION_NONE) {
+                mItems.remove(i);
+                i--;
+
+                if (!isUpdating) {
+                    mAdapter.startUpdate(this);
+                    isUpdating = true;
+                }
+
+                mAdapter.destroyItem(this, ii.position, ii.object);
+                needPopulate = true;
+
+                if (mCurItem == ii.position) {
+                    // Keep the current item in the valid range
+                    newCurrItem = Math.max(0, Math.min(mCurItem, adapterCount - 1));
+                    needPopulate = true;
+                }
+                continue;
+            }
+
+            if (ii.position != newPos) {
+                if (ii.position == mCurItem) {
+                    // Our current item changed position. Follow it.
+                    newCurrItem = newPos;
+                }
+
+                ii.position = newPos;
+                needPopulate = true;
+            }
+        }
+
+        if (isUpdating) {
+            mAdapter.finishUpdate(this);
+        }
+
+        Collections.sort(mItems, COMPARATOR);
+
+        if (needPopulate) {
+            // Reset our known page widths; populate will recompute them.
+            final int childCount = getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                final View child = getChildAt(i);
+                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+                if (!lp.isDecor) {
+                    lp.widthFactor = 0.f;
+                }
+            }
+
+            setCurrentItemInternal(newCurrItem, false, true);
+            requestLayout();
+        }
+    }
+
+    void populate() {
+        populate(mCurItem);
+    }
+
+    void populate(int newCurrentItem) {
+        ItemInfo oldCurInfo = null;
+        if (mCurItem != newCurrentItem) {
+            oldCurInfo = infoForPosition(mCurItem);
+            mCurItem = newCurrentItem;
+        }
+
+        if (mAdapter == null) {
+            sortChildDrawingOrder();
+            return;
+        }
+
+        // Bail now if we are waiting to populate.  This is to hold off
+        // on creating views from the time the user releases their finger to
+        // fling to a new position until we have finished the scroll to
+        // that position, avoiding glitches from happening at that point.
+        if (mPopulatePending) {
+            if (DEBUG) Log.i(TAG, "populate is pending, skipping for now...");
+            sortChildDrawingOrder();
+            return;
+        }
+
+        // Also, don't populate until we are attached to a window.  This is to
+        // avoid trying to populate before we have restored our view hierarchy
+        // state and conflicting with what is restored.
+        if (getWindowToken() == null) {
+            return;
+        }
+
+        mAdapter.startUpdate(this);
+
+        final int pageLimit = mOffscreenPageLimit;
+        final int startPos = Math.max(0, mCurItem - pageLimit);
+        final int N = mAdapter.getCount();
+        final int endPos = Math.min(N - 1, mCurItem + pageLimit);
+
+        if (N != mExpectedAdapterCount) {
+            String resName;
+            try {
+                resName = getResources().getResourceName(getId());
+            } catch (Resources.NotFoundException e) {
+                resName = Integer.toHexString(getId());
+            }
+            throw new IllegalStateException("The application's PagerAdapter changed the adapter's"
+                    + " contents without calling PagerAdapter#notifyDataSetChanged!"
+                    + " Expected adapter item count: " + mExpectedAdapterCount + ", found: " + N
+                    + " Pager id: " + resName
+                    + " Pager class: " + getClass()
+                    + " Problematic adapter: " + mAdapter.getClass());
+        }
+
+        // Locate the currently focused item or add it if needed.
+        int curIndex = -1;
+        ItemInfo curItem = null;
+        for (curIndex = 0; curIndex < mItems.size(); curIndex++) {
+            final ItemInfo ii = mItems.get(curIndex);
+            if (ii.position >= mCurItem) {
+                if (ii.position == mCurItem) curItem = ii;
+                break;
+            }
+        }
+
+        if (curItem == null && N > 0) {
+            curItem = addNewItem(mCurItem, curIndex);
+        }
+
+        // Fill 3x the available width or up to the number of offscreen
+        // pages requested to either side, whichever is larger.
+        // If we have no current item we have no work to do.
+        if (curItem != null) {
+            float extraWidthLeft = 0.f;
+            int itemIndex = curIndex - 1;
+            ItemInfo ii = itemIndex >= 0 ? mItems.get(itemIndex) : null;
+            final int clientWidth = getClientWidth();
+            final float leftWidthNeeded = clientWidth <= 0 ? 0 :
+                    2.f - curItem.widthFactor + (float) getPaddingLeft() / (float) clientWidth;
+            for (int pos = mCurItem - 1; pos >= 0; pos--) {
+                if (extraWidthLeft >= leftWidthNeeded && pos < startPos) {
+                    if (ii == null) {
+                        break;
+                    }
+                    if (pos == ii.position && !ii.scrolling) {
+                        mItems.remove(itemIndex);
+                        mAdapter.destroyItem(this, pos, ii.object);
+                        if (DEBUG) {
+                            Log.i(TAG, "populate() - destroyItem() with pos: " + pos
+                                    + " view: " + ((View) ii.object));
+                        }
+                        itemIndex--;
+                        curIndex--;
+                        ii = itemIndex >= 0 ? mItems.get(itemIndex) : null;
+                    }
+                } else if (ii != null && pos == ii.position) {
+                    extraWidthLeft += ii.widthFactor;
+                    itemIndex--;
+                    ii = itemIndex >= 0 ? mItems.get(itemIndex) : null;
+                } else {
+                    ii = addNewItem(pos, itemIndex + 1);
+                    extraWidthLeft += ii.widthFactor;
+                    curIndex++;
+                    ii = itemIndex >= 0 ? mItems.get(itemIndex) : null;
+                }
+            }
+
+            float extraWidthRight = curItem.widthFactor;
+            itemIndex = curIndex + 1;
+            if (extraWidthRight < 2.f) {
+                ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null;
+                final float rightWidthNeeded = clientWidth <= 0 ? 0 :
+                        (float) getPaddingRight() / (float) clientWidth + 2.f;
+                for (int pos = mCurItem + 1; pos < N; pos++) {
+                    if (extraWidthRight >= rightWidthNeeded && pos > endPos) {
+                        if (ii == null) {
+                            break;
+                        }
+                        if (pos == ii.position && !ii.scrolling) {
+                            mItems.remove(itemIndex);
+                            mAdapter.destroyItem(this, pos, ii.object);
+                            if (DEBUG) {
+                                Log.i(TAG, "populate() - destroyItem() with pos: " + pos
+                                        + " view: " + ((View) ii.object));
+                            }
+                            ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null;
+                        }
+                    } else if (ii != null && pos == ii.position) {
+                        extraWidthRight += ii.widthFactor;
+                        itemIndex++;
+                        ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null;
+                    } else {
+                        ii = addNewItem(pos, itemIndex);
+                        itemIndex++;
+                        extraWidthRight += ii.widthFactor;
+                        ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null;
+                    }
+                }
+            }
+
+            calculatePageOffsets(curItem, curIndex, oldCurInfo);
+
+            mAdapter.setPrimaryItem(this, mCurItem, curItem.object);
+        }
+
+        if (DEBUG) {
+            Log.i(TAG, "Current page list:");
+            for (int i = 0; i < mItems.size(); i++) {
+                Log.i(TAG, "#" + i + ": page " + mItems.get(i).position);
+            }
+        }
+
+        mAdapter.finishUpdate(this);
+
+        // Check width measurement of current pages and drawing sort order.
+        // Update LayoutParams as needed.
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final View child = getChildAt(i);
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+            lp.childIndex = i;
+            if (!lp.isDecor && lp.widthFactor == 0.f) {
+                // 0 means requery the adapter for this, it doesn't have a valid width.
+                final ItemInfo ii = infoForChild(child);
+                if (ii != null) {
+                    lp.widthFactor = ii.widthFactor;
+                    lp.position = ii.position;
+                }
+            }
+        }
+        sortChildDrawingOrder();
+
+        if (hasFocus()) {
+            View currentFocused = findFocus();
+            ItemInfo ii = currentFocused != null ? infoForAnyChild(currentFocused) : null;
+            if (ii == null || ii.position != mCurItem) {
+                for (int i = 0; i < getChildCount(); i++) {
+                    View child = getChildAt(i);
+                    ii = infoForChild(child);
+                    if (ii != null && ii.position == mCurItem) {
+                        if (child.requestFocus(View.FOCUS_FORWARD)) {
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private void sortChildDrawingOrder() {
+        if (mDrawingOrder != DRAW_ORDER_DEFAULT) {
+            if (mDrawingOrderedChildren == null) {
+                mDrawingOrderedChildren = new ArrayList<View>();
+            } else {
+                mDrawingOrderedChildren.clear();
+            }
+            final int childCount = getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                final View child = getChildAt(i);
+                mDrawingOrderedChildren.add(child);
+            }
+            Collections.sort(mDrawingOrderedChildren, sPositionComparator);
+        }
+    }
+
+    private void calculatePageOffsets(ItemInfo curItem, int curIndex, ItemInfo oldCurInfo) {
+        final int N = mAdapter.getCount();
+        final int width = getClientWidth();
+        final float marginOffset = width > 0 ? (float) mPageMargin / width : 0;
+        // Fix up offsets for later layout.
+        if (oldCurInfo != null) {
+            final int oldCurPosition = oldCurInfo.position;
+            // Base offsets off of oldCurInfo.
+            if (oldCurPosition < curItem.position) {
+                int itemIndex = 0;
+                ItemInfo ii = null;
+                float offset = oldCurInfo.offset + oldCurInfo.widthFactor + marginOffset;
+                for (int pos = oldCurPosition + 1;
+                        pos <= curItem.position && itemIndex < mItems.size(); pos++) {
+                    ii = mItems.get(itemIndex);
+                    while (pos > ii.position && itemIndex < mItems.size() - 1) {
+                        itemIndex++;
+                        ii = mItems.get(itemIndex);
+                    }
+                    while (pos < ii.position) {
+                        // We don't have an item populated for this,
+                        // ask the adapter for an offset.
+                        offset += mAdapter.getPageWidth(pos) + marginOffset;
+                        pos++;
+                    }
+                    ii.offset = offset;
+                    offset += ii.widthFactor + marginOffset;
+                }
+            } else if (oldCurPosition > curItem.position) {
+                int itemIndex = mItems.size() - 1;
+                ItemInfo ii = null;
+                float offset = oldCurInfo.offset;
+                for (int pos = oldCurPosition - 1;
+                        pos >= curItem.position && itemIndex >= 0; pos--) {
+                    ii = mItems.get(itemIndex);
+                    while (pos < ii.position && itemIndex > 0) {
+                        itemIndex--;
+                        ii = mItems.get(itemIndex);
+                    }
+                    while (pos > ii.position) {
+                        // We don't have an item populated for this,
+                        // ask the adapter for an offset.
+                        offset -= mAdapter.getPageWidth(pos) + marginOffset;
+                        pos--;
+                    }
+                    offset -= ii.widthFactor + marginOffset;
+                    ii.offset = offset;
+                }
+            }
+        }
+
+        // Base all offsets off of curItem.
+        final int itemCount = mItems.size();
+        float offset = curItem.offset;
+        int pos = curItem.position - 1;
+        mFirstOffset = curItem.position == 0 ? curItem.offset : -Float.MAX_VALUE;
+        mLastOffset = curItem.position == N - 1
+                ? curItem.offset + curItem.widthFactor - 1 : Float.MAX_VALUE;
+        // Previous pages
+        for (int i = curIndex - 1; i >= 0; i--, pos--) {
+            final ItemInfo ii = mItems.get(i);
+            while (pos > ii.position) {
+                offset -= mAdapter.getPageWidth(pos--) + marginOffset;
+            }
+            offset -= ii.widthFactor + marginOffset;
+            ii.offset = offset;
+            if (ii.position == 0) mFirstOffset = offset;
+        }
+        offset = curItem.offset + curItem.widthFactor + marginOffset;
+        pos = curItem.position + 1;
+        // Next pages
+        for (int i = curIndex + 1; i < itemCount; i++, pos++) {
+            final ItemInfo ii = mItems.get(i);
+            while (pos < ii.position) {
+                offset += mAdapter.getPageWidth(pos++) + marginOffset;
+            }
+            if (ii.position == N - 1) {
+                mLastOffset = offset + ii.widthFactor - 1;
+            }
+            ii.offset = offset;
+            offset += ii.widthFactor + marginOffset;
+        }
+
+        mNeedCalculatePageOffsets = false;
+    }
+
+    /**
+     * This is the persistent state that is saved by ViewPager.  Only needed
+     * if you are creating a sublass of ViewPager that must save its own
+     * state, in which case it should implement a subclass of this which
+     * contains that state.
+     */
+    public static class SavedState extends AbsSavedState {
+        int position;
+        Parcelable adapterState;
+        ClassLoader loader;
+
+        public SavedState(@NonNull Parcelable superState) {
+            super(superState);
+        }
+
+        @Override
+        public void writeToParcel(Parcel out, int flags) {
+            super.writeToParcel(out, flags);
+            out.writeInt(position);
+            out.writeParcelable(adapterState, flags);
+        }
+
+        @Override
+        public String toString() {
+            return "FragmentPager.SavedState{"
+                    + Integer.toHexString(System.identityHashCode(this))
+                    + " position=" + position + "}";
+        }
+
+        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];
+            }
+        };
+
+        SavedState(Parcel in, ClassLoader loader) {
+            super(in, loader);
+            if (loader == null) {
+                loader = getClass().getClassLoader();
+            }
+            position = in.readInt();
+            adapterState = in.readParcelable(loader);
+            this.loader = loader;
+        }
+    }
+
+    @Override
+    public Parcelable onSaveInstanceState() {
+        Parcelable superState = super.onSaveInstanceState();
+        SavedState ss = new SavedState(superState);
+        ss.position = mCurItem;
+        if (mAdapter != null) {
+            ss.adapterState = mAdapter.saveState();
+        }
+        return ss;
+    }
+
+    @Override
+    public void onRestoreInstanceState(Parcelable state) {
+        if (!(state instanceof SavedState)) {
+            super.onRestoreInstanceState(state);
+            return;
+        }
+
+        SavedState ss = (SavedState) state;
+        super.onRestoreInstanceState(ss.getSuperState());
+
+        if (mAdapter != null) {
+            mAdapter.restoreState(ss.adapterState, ss.loader);
+            setCurrentItemInternal(ss.position, false, true);
+        } else {
+            mRestoredCurItem = ss.position;
+            mRestoredAdapterState = ss.adapterState;
+            mRestoredClassLoader = ss.loader;
+        }
+    }
+
+    @Override
+    public void addView(View child, int index, ViewGroup.LayoutParams params) {
+        if (!checkLayoutParams(params)) {
+            params = generateLayoutParams(params);
+        }
+        final LayoutParams lp = (LayoutParams) params;
+        // Any views added via inflation should be classed as part of the decor
+        lp.isDecor |= isDecorView(child);
+        if (mInLayout) {
+            if (lp != null && lp.isDecor) {
+                throw new IllegalStateException("Cannot add pager decor view during layout");
+            }
+            lp.needsMeasure = true;
+            addViewInLayout(child, index, params);
+        } else {
+            super.addView(child, index, params);
+        }
+
+        if (USE_CACHE) {
+            if (child.getVisibility() != GONE) {
+                child.setDrawingCacheEnabled(mScrollingCacheEnabled);
+            } else {
+                child.setDrawingCacheEnabled(false);
+            }
+        }
+    }
+
+    private static boolean isDecorView(@NonNull View view) {
+        Class<?> clazz = view.getClass();
+        return clazz.getAnnotation(DecorView.class) != null;
+    }
+
+    @Override
+    public void removeView(View view) {
+        if (mInLayout) {
+            removeViewInLayout(view);
+        } else {
+            super.removeView(view);
+        }
+    }
+
+    ItemInfo infoForChild(View child) {
+        for (int i = 0; i < mItems.size(); i++) {
+            ItemInfo ii = mItems.get(i);
+            if (mAdapter.isViewFromObject(child, ii.object)) {
+                return ii;
+            }
+        }
+        return null;
+    }
+
+    ItemInfo infoForAnyChild(View child) {
+        ViewParent parent;
+        while ((parent = child.getParent()) != this) {
+            if (parent == null || !(parent instanceof View)) {
+                return null;
+            }
+            child = (View) parent;
+        }
+        return infoForChild(child);
+    }
+
+    ItemInfo infoForPosition(int position) {
+        for (int i = 0; i < mItems.size(); i++) {
+            ItemInfo ii = mItems.get(i);
+            if (ii.position == position) {
+                return ii;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        mFirstLayout = true;
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        // For simple implementation, our internal size is always 0.
+        // We depend on the container to specify the layout size of
+        // our view.  We can't really know what it is since we will be
+        // adding and removing different arbitrary views and do not
+        // want the layout to change as this happens.
+        setMeasuredDimension(getDefaultSize(0, widthMeasureSpec),
+                getDefaultSize(0, heightMeasureSpec));
+
+        final int measuredWidth = getMeasuredWidth();
+        final int maxGutterSize = measuredWidth / 10;
+        mGutterSize = Math.min(maxGutterSize, mDefaultGutterSize);
+
+        // Children are just made to fill our space.
+        int childWidthSize = measuredWidth - getPaddingLeft() - getPaddingRight();
+        int childHeightSize = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
+
+        /*
+         * Make sure all children have been properly measured. Decor views first.
+         * Right now we cheat and make this less complicated by assuming decor
+         * views won't intersect. We will pin to edges based on gravity.
+         */
+        int size = getChildCount();
+        for (int i = 0; i < size; ++i) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() != GONE) {
+                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+                if (lp != null && lp.isDecor) {
+                    final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
+                    final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK;
+                    int widthMode = MeasureSpec.AT_MOST;
+                    int heightMode = MeasureSpec.AT_MOST;
+                    boolean consumeVertical = vgrav == Gravity.TOP || vgrav == Gravity.BOTTOM;
+                    boolean consumeHorizontal = hgrav == Gravity.LEFT || hgrav == Gravity.RIGHT;
+
+                    if (consumeVertical) {
+                        widthMode = MeasureSpec.EXACTLY;
+                    } else if (consumeHorizontal) {
+                        heightMode = MeasureSpec.EXACTLY;
+                    }
+
+                    int widthSize = childWidthSize;
+                    int heightSize = childHeightSize;
+                    if (lp.width != LayoutParams.WRAP_CONTENT) {
+                        widthMode = MeasureSpec.EXACTLY;
+                        if (lp.width != LayoutParams.MATCH_PARENT) {
+                            widthSize = lp.width;
+                        }
+                    }
+                    if (lp.height != LayoutParams.WRAP_CONTENT) {
+                        heightMode = MeasureSpec.EXACTLY;
+                        if (lp.height != LayoutParams.MATCH_PARENT) {
+                            heightSize = lp.height;
+                        }
+                    }
+                    final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, widthMode);
+                    final int heightSpec = MeasureSpec.makeMeasureSpec(heightSize, heightMode);
+                    child.measure(widthSpec, heightSpec);
+
+                    if (consumeVertical) {
+                        childHeightSize -= child.getMeasuredHeight();
+                    } else if (consumeHorizontal) {
+                        childWidthSize -= child.getMeasuredWidth();
+                    }
+                }
+            }
+        }
+
+        mChildWidthMeasureSpec = MeasureSpec.makeMeasureSpec(childWidthSize, MeasureSpec.EXACTLY);
+        mChildHeightMeasureSpec = MeasureSpec.makeMeasureSpec(childHeightSize, MeasureSpec.EXACTLY);
+
+        // Make sure we have created all fragments that we need to have shown.
+        mInLayout = true;
+        populate();
+        mInLayout = false;
+
+        // Page views next.
+        size = getChildCount();
+        for (int i = 0; i < size; ++i) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() != GONE) {
+                if (DEBUG) {
+                    Log.v(TAG, "Measuring #" + i + " " + child + ": " + mChildWidthMeasureSpec);
+                }
+
+                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+                if (lp == null || !lp.isDecor) {
+                    final int widthSpec = MeasureSpec.makeMeasureSpec(
+                            (int) (childWidthSize * lp.widthFactor), MeasureSpec.EXACTLY);
+                    child.measure(widthSpec, mChildHeightMeasureSpec);
+                }
+            }
+        }
+    }
+
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        super.onSizeChanged(w, h, oldw, oldh);
+
+        // Make sure scroll position is set correctly.
+        if (w != oldw) {
+            recomputeScrollPosition(w, oldw, mPageMargin, mPageMargin);
+        }
+    }
+
+    private void recomputeScrollPosition(int width, int oldWidth, int margin, int oldMargin) {
+        if (oldWidth > 0 && !mItems.isEmpty()) {
+            if (!mScroller.isFinished()) {
+                mScroller.setFinalX(getCurrentItem() * getClientWidth());
+            } else {
+                final int widthWithMargin = width - getPaddingLeft() - getPaddingRight() + margin;
+                final int oldWidthWithMargin = oldWidth - getPaddingLeft() - getPaddingRight()
+                        + oldMargin;
+                final int xpos = getScrollX();
+                final float pageOffset = (float) xpos / oldWidthWithMargin;
+                final int newOffsetPixels = (int) (pageOffset * widthWithMargin);
+
+                scrollTo(newOffsetPixels, getScrollY());
+            }
+        } else {
+            final ItemInfo ii = infoForPosition(mCurItem);
+            final float scrollOffset = ii != null ? Math.min(ii.offset, mLastOffset) : 0;
+            final int scrollPos =
+                    (int) (scrollOffset * (width - getPaddingLeft() - getPaddingRight()));
+            if (scrollPos != getScrollX()) {
+                completeScroll(false);
+                scrollTo(scrollPos, getScrollY());
+            }
+        }
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        final int count = getChildCount();
+        int width = r - l;
+        int height = b - t;
+        int paddingLeft = getPaddingLeft();
+        int paddingTop = getPaddingTop();
+        int paddingRight = getPaddingRight();
+        int paddingBottom = getPaddingBottom();
+        final int scrollX = getScrollX();
+
+        int decorCount = 0;
+
+        // First pass - decor views. We need to do this in two passes so that
+        // we have the proper offsets for non-decor views later.
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() != GONE) {
+                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+                int childLeft = 0;
+                int childTop = 0;
+                if (lp.isDecor) {
+                    final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
+                    final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK;
+                    switch (hgrav) {
+                        default:
+                            childLeft = paddingLeft;
+                            break;
+                        case Gravity.LEFT:
+                            childLeft = paddingLeft;
+                            paddingLeft += child.getMeasuredWidth();
+                            break;
+                        case Gravity.CENTER_HORIZONTAL:
+                            childLeft = Math.max((width - child.getMeasuredWidth()) / 2,
+                                    paddingLeft);
+                            break;
+                        case Gravity.RIGHT:
+                            childLeft = width - paddingRight - child.getMeasuredWidth();
+                            paddingRight += child.getMeasuredWidth();
+                            break;
+                    }
+                    switch (vgrav) {
+                        default:
+                            childTop = paddingTop;
+                            break;
+                        case Gravity.TOP:
+                            childTop = paddingTop;
+                            paddingTop += child.getMeasuredHeight();
+                            break;
+                        case Gravity.CENTER_VERTICAL:
+                            childTop = Math.max((height - child.getMeasuredHeight()) / 2,
+                                    paddingTop);
+                            break;
+                        case Gravity.BOTTOM:
+                            childTop = height - paddingBottom - child.getMeasuredHeight();
+                            paddingBottom += child.getMeasuredHeight();
+                            break;
+                    }
+                    childLeft += scrollX;
+                    child.layout(childLeft, childTop,
+                            childLeft + child.getMeasuredWidth(),
+                            childTop + child.getMeasuredHeight());
+                    decorCount++;
+                }
+            }
+        }
+
+        final int childWidth = width - paddingLeft - paddingRight;
+        // Page views. Do this once we have the right padding offsets from above.
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() != GONE) {
+                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+                ItemInfo ii;
+                if (!lp.isDecor && (ii = infoForChild(child)) != null) {
+                    int loff = (int) (childWidth * ii.offset);
+                    int childLeft = paddingLeft + loff;
+                    int childTop = paddingTop;
+                    if (lp.needsMeasure) {
+                        // This was added during layout and needs measurement.
+                        // Do it now that we know what we're working with.
+                        lp.needsMeasure = false;
+                        final int widthSpec = MeasureSpec.makeMeasureSpec(
+                                (int) (childWidth * lp.widthFactor),
+                                MeasureSpec.EXACTLY);
+                        final int heightSpec = MeasureSpec.makeMeasureSpec(
+                                (int) (height - paddingTop - paddingBottom),
+                                MeasureSpec.EXACTLY);
+                        child.measure(widthSpec, heightSpec);
+                    }
+                    if (DEBUG) {
+                        Log.v(TAG, "Positioning #" + i + " " + child + " f=" + ii.object
+                                + ":" + childLeft + "," + childTop + " " + child.getMeasuredWidth()
+                                + "x" + child.getMeasuredHeight());
+                    }
+                    child.layout(childLeft, childTop,
+                            childLeft + child.getMeasuredWidth(),
+                            childTop + child.getMeasuredHeight());
+                }
+            }
+        }
+        mTopPageBounds = paddingTop;
+        mBottomPageBounds = height - paddingBottom;
+        mDecorChildCount = decorCount;
+
+        if (mFirstLayout) {
+            scrollToItem(mCurItem, false, 0, false);
+        }
+        mFirstLayout = false;
+    }
+
+    @Override
+    public void computeScroll() {
+        mIsScrollStarted = true;
+        if (!mScroller.isFinished() && mScroller.computeScrollOffset()) {
+            int oldX = getScrollX();
+            int oldY = getScrollY();
+            int x = mScroller.getCurrX();
+            int y = mScroller.getCurrY();
+
+            if (oldX != x || oldY != y) {
+                scrollTo(x, y);
+                if (!pageScrolled(x)) {
+                    mScroller.abortAnimation();
+                    scrollTo(0, y);
+                }
+            }
+
+            // Keep on drawing until the animation has finished.
+            ViewCompat.postInvalidateOnAnimation(this);
+            return;
+        }
+
+        // Done with scroll, clean up state.
+        completeScroll(true);
+    }
+
+    private boolean pageScrolled(int xpos) {
+        if (mItems.size() == 0) {
+            if (mFirstLayout) {
+                // If we haven't been laid out yet, we probably just haven't been populated yet.
+                // Let's skip this call since it doesn't make sense in this state
+                return false;
+            }
+            mCalledSuper = false;
+            onPageScrolled(0, 0, 0);
+            if (!mCalledSuper) {
+                throw new IllegalStateException(
+                        "onPageScrolled did not call superclass implementation");
+            }
+            return false;
+        }
+        final ItemInfo ii = infoForCurrentScrollPosition();
+        final int width = getClientWidth();
+        final int widthWithMargin = width + mPageMargin;
+        final float marginOffset = (float) mPageMargin / width;
+        final int currentPage = ii.position;
+        final float pageOffset = (((float) xpos / width) - ii.offset)
+                / (ii.widthFactor + marginOffset);
+        final int offsetPixels = (int) (pageOffset * widthWithMargin);
+
+        mCalledSuper = false;
+        onPageScrolled(currentPage, pageOffset, offsetPixels);
+        if (!mCalledSuper) {
+            throw new IllegalStateException(
+                    "onPageScrolled did not call superclass implementation");
+        }
+        return true;
+    }
+
+    /**
+     * This method will be invoked when the current page is scrolled, either as part
+     * of a programmatically initiated smooth scroll or a user initiated touch scroll.
+     * If you override this method you must call through to the superclass implementation
+     * (e.g. super.onPageScrolled(position, offset, offsetPixels)) before onPageScrolled
+     * returns.
+     *
+     * @param position Position index of the first page currently being displayed.
+     *                 Page position+1 will be visible if positionOffset is nonzero.
+     * @param offset Value from [0, 1) indicating the offset from the page at position.
+     * @param offsetPixels Value in pixels indicating the offset from position.
+     */
+    @CallSuper
+    protected void onPageScrolled(int position, float offset, int offsetPixels) {
+        // Offset any decor views if needed - keep them on-screen at all times.
+        if (mDecorChildCount > 0) {
+            final int scrollX = getScrollX();
+            int paddingLeft = getPaddingLeft();
+            int paddingRight = getPaddingRight();
+            final int width = getWidth();
+            final int childCount = getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                final View child = getChildAt(i);
+                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+                if (!lp.isDecor) continue;
+
+                final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
+                int childLeft = 0;
+                switch (hgrav) {
+                    default:
+                        childLeft = paddingLeft;
+                        break;
+                    case Gravity.LEFT:
+                        childLeft = paddingLeft;
+                        paddingLeft += child.getWidth();
+                        break;
+                    case Gravity.CENTER_HORIZONTAL:
+                        childLeft = Math.max((width - child.getMeasuredWidth()) / 2,
+                                paddingLeft);
+                        break;
+                    case Gravity.RIGHT:
+                        childLeft = width - paddingRight - child.getMeasuredWidth();
+                        paddingRight += child.getMeasuredWidth();
+                        break;
+                }
+                childLeft += scrollX;
+
+                final int childOffset = childLeft - child.getLeft();
+                if (childOffset != 0) {
+                    child.offsetLeftAndRight(childOffset);
+                }
+            }
+        }
+
+        dispatchOnPageScrolled(position, offset, offsetPixels);
+
+        if (mPageTransformer != null) {
+            final int scrollX = getScrollX();
+            final int childCount = getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                final View child = getChildAt(i);
+                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+                if (lp.isDecor) continue;
+                final float transformPos = (float) (child.getLeft() - scrollX) / getClientWidth();
+                mPageTransformer.transformPage(child, transformPos);
+            }
+        }
+
+        mCalledSuper = true;
+    }
+
+    private void dispatchOnPageScrolled(int position, float offset, int offsetPixels) {
+        if (mOnPageChangeListener != null) {
+            mOnPageChangeListener.onPageScrolled(position, offset, offsetPixels);
+        }
+        if (mOnPageChangeListeners != null) {
+            for (int i = 0, z = mOnPageChangeListeners.size(); i < z; i++) {
+                OnPageChangeListener listener = mOnPageChangeListeners.get(i);
+                if (listener != null) {
+                    listener.onPageScrolled(position, offset, offsetPixels);
+                }
+            }
+        }
+        if (mInternalPageChangeListener != null) {
+            mInternalPageChangeListener.onPageScrolled(position, offset, offsetPixels);
+        }
+    }
+
+    private void dispatchOnPageSelected(int position) {
+        if (mOnPageChangeListener != null) {
+            mOnPageChangeListener.onPageSelected(position);
+        }
+        if (mOnPageChangeListeners != null) {
+            for (int i = 0, z = mOnPageChangeListeners.size(); i < z; i++) {
+                OnPageChangeListener listener = mOnPageChangeListeners.get(i);
+                if (listener != null) {
+                    listener.onPageSelected(position);
+                }
+            }
+        }
+        if (mInternalPageChangeListener != null) {
+            mInternalPageChangeListener.onPageSelected(position);
+        }
+    }
+
+    private void dispatchOnScrollStateChanged(int state) {
+        if (mOnPageChangeListener != null) {
+            mOnPageChangeListener.onPageScrollStateChanged(state);
+        }
+        if (mOnPageChangeListeners != null) {
+            for (int i = 0, z = mOnPageChangeListeners.size(); i < z; i++) {
+                OnPageChangeListener listener = mOnPageChangeListeners.get(i);
+                if (listener != null) {
+                    listener.onPageScrollStateChanged(state);
+                }
+            }
+        }
+        if (mInternalPageChangeListener != null) {
+            mInternalPageChangeListener.onPageScrollStateChanged(state);
+        }
+    }
+
+    private void completeScroll(boolean postEvents) {
+        boolean needPopulate = mScrollState == SCROLL_STATE_SETTLING;
+        if (needPopulate) {
+            // Done with scroll, no longer want to cache view drawing.
+            setScrollingCacheEnabled(false);
+            boolean wasScrolling = !mScroller.isFinished();
+            if (wasScrolling) {
+                mScroller.abortAnimation();
+                int oldX = getScrollX();
+                int oldY = getScrollY();
+                int x = mScroller.getCurrX();
+                int y = mScroller.getCurrY();
+                if (oldX != x || oldY != y) {
+                    scrollTo(x, y);
+                    if (x != oldX) {
+                        pageScrolled(x);
+                    }
+                }
+            }
+        }
+        mPopulatePending = false;
+        for (int i = 0; i < mItems.size(); i++) {
+            ItemInfo ii = mItems.get(i);
+            if (ii.scrolling) {
+                needPopulate = true;
+                ii.scrolling = false;
+            }
+        }
+        if (needPopulate) {
+            if (postEvents) {
+                ViewCompat.postOnAnimation(this, mEndScrollRunnable);
+            } else {
+                mEndScrollRunnable.run();
+            }
+        }
+    }
+
+    private boolean isGutterDrag(float x, float dx) {
+        return (x < mGutterSize && dx > 0) || (x > getWidth() - mGutterSize && dx < 0);
+    }
+
+    private void enableLayers(boolean enable) {
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final int layerType = enable
+                    ? mPageTransformerLayerType : View.LAYER_TYPE_NONE;
+            getChildAt(i).setLayerType(layerType, null);
+        }
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        /*
+         * This method JUST determines whether we want to intercept the motion.
+         * If we return true, onMotionEvent will be called and we do the actual
+         * scrolling there.
+         */
+
+        final int action = ev.getAction() & MotionEvent.ACTION_MASK;
+
+        // Always take care of the touch gesture being complete.
+        if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
+            // Release the drag.
+            if (DEBUG) Log.v(TAG, "Intercept done!");
+            resetTouch();
+            return false;
+        }
+
+        // Nothing more to do here if we have decided whether or not we
+        // are dragging.
+        if (action != MotionEvent.ACTION_DOWN) {
+            if (mIsBeingDragged) {
+                if (DEBUG) Log.v(TAG, "Intercept returning true!");
+                return true;
+            }
+            if (mIsUnableToDrag) {
+                if (DEBUG) Log.v(TAG, "Intercept returning false!");
+                return false;
+            }
+        }
+
+        switch (action) {
+            case MotionEvent.ACTION_MOVE: {
+                /*
+                 * mIsBeingDragged == false, otherwise the shortcut would have caught it. Check
+                 * whether the user has moved far enough from his original down touch.
+                 */
+
+                /*
+                * Locally do absolute value. mLastMotionY is set to the y value
+                * of the down event.
+                */
+                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);
+                final float x = ev.getX(pointerIndex);
+                final float dx = x - mLastMotionX;
+                final float xDiff = Math.abs(dx);
+                final float y = ev.getY(pointerIndex);
+                final float yDiff = Math.abs(y - mInitialMotionY);
+                if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff);
+
+                if (dx != 0 && !isGutterDrag(mLastMotionX, dx)
+                        && canScroll(this, false, (int) dx, (int) x, (int) y)) {
+                    // Nested view has scrollable area under this point. Let it be handled there.
+                    mLastMotionX = x;
+                    mLastMotionY = y;
+                    mIsUnableToDrag = true;
+                    return false;
+                }
+                if (xDiff > mTouchSlop && xDiff * 0.5f > yDiff) {
+                    if (DEBUG) Log.v(TAG, "Starting drag!");
+                    mIsBeingDragged = true;
+                    requestParentDisallowInterceptTouchEvent(true);
+                    setScrollState(SCROLL_STATE_DRAGGING);
+                    mLastMotionX = dx > 0
+                            ? mInitialMotionX + mTouchSlop : mInitialMotionX - mTouchSlop;
+                    mLastMotionY = y;
+                    setScrollingCacheEnabled(true);
+                } else if (yDiff > mTouchSlop) {
+                    // The finger has moved enough in the vertical
+                    // direction to be counted as a drag...  abort
+                    // any attempt to drag horizontally, to work correctly
+                    // with children that have scrolling containers.
+                    if (DEBUG) Log.v(TAG, "Starting unable to drag!");
+                    mIsUnableToDrag = true;
+                }
+                if (mIsBeingDragged) {
+                    // Scroll to follow the motion event
+                    if (performDrag(x)) {
+                        ViewCompat.postInvalidateOnAnimation(this);
+                    }
+                }
+                break;
+            }
+
+            case MotionEvent.ACTION_DOWN: {
+                /*
+                 * Remember location of down touch.
+                 * ACTION_DOWN always refers to pointer index 0.
+                 */
+                mLastMotionX = mInitialMotionX = ev.getX();
+                mLastMotionY = mInitialMotionY = ev.getY();
+                mActivePointerId = ev.getPointerId(0);
+                mIsUnableToDrag = false;
+
+                mIsScrollStarted = true;
+                mScroller.computeScrollOffset();
+                if (mScrollState == SCROLL_STATE_SETTLING
+                        && Math.abs(mScroller.getFinalX() - mScroller.getCurrX()) > mCloseEnough) {
+                    // Let the user 'catch' the pager as it animates.
+                    mScroller.abortAnimation();
+                    mPopulatePending = false;
+                    populate();
+                    mIsBeingDragged = true;
+                    requestParentDisallowInterceptTouchEvent(true);
+                    setScrollState(SCROLL_STATE_DRAGGING);
+                } else {
+                    completeScroll(false);
+                    mIsBeingDragged = false;
+                }
+
+                if (DEBUG) {
+                    Log.v(TAG, "Down at " + mLastMotionX + "," + mLastMotionY
+                            + " mIsBeingDragged=" + mIsBeingDragged
+                            + "mIsUnableToDrag=" + mIsUnableToDrag);
+                }
+                break;
+            }
+
+            case MotionEvent.ACTION_POINTER_UP:
+                onSecondaryPointerUp(ev);
+                break;
+        }
+
+        if (mVelocityTracker == null) {
+            mVelocityTracker = VelocityTracker.obtain();
+        }
+        mVelocityTracker.addMovement(ev);
+
+        /*
+         * The only time we want to intercept motion events is if we are in the
+         * drag mode.
+         */
+        return mIsBeingDragged;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        if (mFakeDragging) {
+            // A fake drag is in progress already, ignore this real one
+            // but still eat the touch events.
+            // (It is likely that the user is multi-touching the screen.)
+            return true;
+        }
+
+        if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) {
+            // Don't handle edge touches immediately -- they may actually belong to one of our
+            // descendants.
+            return false;
+        }
+
+        if (mAdapter == null || mAdapter.getCount() == 0) {
+            // Nothing to present or scroll; nothing to touch.
+            return false;
+        }
+
+        if (mVelocityTracker == null) {
+            mVelocityTracker = VelocityTracker.obtain();
+        }
+        mVelocityTracker.addMovement(ev);
+
+        final int action = ev.getAction();
+        boolean needsInvalidate = false;
+
+        switch (action & MotionEvent.ACTION_MASK) {
+            case MotionEvent.ACTION_DOWN: {
+                mScroller.abortAnimation();
+                mPopulatePending = false;
+                populate();
+
+                // Remember where the motion event started
+                mLastMotionX = mInitialMotionX = ev.getX();
+                mLastMotionY = mInitialMotionY = ev.getY();
+                mActivePointerId = ev.getPointerId(0);
+                break;
+            }
+            case MotionEvent.ACTION_MOVE:
+                if (!mIsBeingDragged) {
+                    final int pointerIndex = ev.findPointerIndex(mActivePointerId);
+                    if (pointerIndex == -1) {
+                        // A child has consumed some touch events and put us into an inconsistent
+                        // state.
+                        needsInvalidate = resetTouch();
+                        break;
+                    }
+                    final float x = ev.getX(pointerIndex);
+                    final float xDiff = Math.abs(x - mLastMotionX);
+                    final float y = ev.getY(pointerIndex);
+                    final float yDiff = Math.abs(y - mLastMotionY);
+                    if (DEBUG) {
+                        Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff);
+                    }
+                    if (xDiff > mTouchSlop && xDiff > yDiff) {
+                        if (DEBUG) Log.v(TAG, "Starting drag!");
+                        mIsBeingDragged = true;
+                        requestParentDisallowInterceptTouchEvent(true);
+                        mLastMotionX = x - mInitialMotionX > 0 ? mInitialMotionX + mTouchSlop :
+                                mInitialMotionX - mTouchSlop;
+                        mLastMotionY = y;
+                        setScrollState(SCROLL_STATE_DRAGGING);
+                        setScrollingCacheEnabled(true);
+
+                        // Disallow Parent Intercept, just in case
+                        ViewParent parent = getParent();
+                        if (parent != null) {
+                            parent.requestDisallowInterceptTouchEvent(true);
+                        }
+                    }
+                }
+                // Not else! Note that mIsBeingDragged can be set above.
+                if (mIsBeingDragged) {
+                    // Scroll to follow the motion event
+                    final int activePointerIndex = ev.findPointerIndex(mActivePointerId);
+                    final float x = ev.getX(activePointerIndex);
+                    needsInvalidate |= performDrag(x);
+                }
+                break;
+            case MotionEvent.ACTION_UP:
+                if (mIsBeingDragged) {
+                    final VelocityTracker velocityTracker = mVelocityTracker;
+                    velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
+                    int initialVelocity = (int) velocityTracker.getXVelocity(mActivePointerId);
+                    mPopulatePending = true;
+                    final int width = getClientWidth();
+                    final int scrollX = getScrollX();
+                    final ItemInfo ii = infoForCurrentScrollPosition();
+                    final float marginOffset = (float) mPageMargin / width;
+                    final int currentPage = ii.position;
+                    final float pageOffset = (((float) scrollX / width) - ii.offset)
+                            / (ii.widthFactor + marginOffset);
+                    final int activePointerIndex = ev.findPointerIndex(mActivePointerId);
+                    final float x = ev.getX(activePointerIndex);
+                    final int totalDelta = (int) (x - mInitialMotionX);
+                    int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity,
+                            totalDelta);
+                    setCurrentItemInternal(nextPage, true, true, initialVelocity);
+
+                    needsInvalidate = resetTouch();
+                }
+                break;
+            case MotionEvent.ACTION_CANCEL:
+                if (mIsBeingDragged) {
+                    scrollToItem(mCurItem, true, 0, false);
+                    needsInvalidate = resetTouch();
+                }
+                break;
+            case MotionEvent.ACTION_POINTER_DOWN: {
+                final int index = ev.getActionIndex();
+                final float x = ev.getX(index);
+                mLastMotionX = x;
+                mActivePointerId = ev.getPointerId(index);
+                break;
+            }
+            case MotionEvent.ACTION_POINTER_UP:
+                onSecondaryPointerUp(ev);
+                mLastMotionX = ev.getX(ev.findPointerIndex(mActivePointerId));
+                break;
+        }
+        if (needsInvalidate) {
+            ViewCompat.postInvalidateOnAnimation(this);
+        }
+        return true;
+    }
+
+    private boolean resetTouch() {
+        boolean needsInvalidate;
+        mActivePointerId = INVALID_POINTER;
+        endDrag();
+        mLeftEdge.onRelease();
+        mRightEdge.onRelease();
+        needsInvalidate = mLeftEdge.isFinished() || mRightEdge.isFinished();
+        return needsInvalidate;
+    }
+
+    private void requestParentDisallowInterceptTouchEvent(boolean disallowIntercept) {
+        final ViewParent parent = getParent();
+        if (parent != null) {
+            parent.requestDisallowInterceptTouchEvent(disallowIntercept);
+        }
+    }
+
+    private boolean performDrag(float x) {
+        boolean needsInvalidate = false;
+
+        final float deltaX = mLastMotionX - x;
+        mLastMotionX = x;
+
+        float oldScrollX = getScrollX();
+        float scrollX = oldScrollX + deltaX;
+        final int width = getClientWidth();
+
+        float leftBound = width * mFirstOffset;
+        float rightBound = width * mLastOffset;
+        boolean leftAbsolute = true;
+        boolean rightAbsolute = true;
+
+        final ItemInfo firstItem = mItems.get(0);
+        final ItemInfo lastItem = mItems.get(mItems.size() - 1);
+        if (firstItem.position != 0) {
+            leftAbsolute = false;
+            leftBound = firstItem.offset * width;
+        }
+        if (lastItem.position != mAdapter.getCount() - 1) {
+            rightAbsolute = false;
+            rightBound = lastItem.offset * width;
+        }
+
+        if (scrollX < leftBound) {
+            if (leftAbsolute) {
+                float over = leftBound - scrollX;
+                mLeftEdge.onPull(Math.abs(over) / width);
+                needsInvalidate = true;
+            }
+            scrollX = leftBound;
+        } else if (scrollX > rightBound) {
+            if (rightAbsolute) {
+                float over = scrollX - rightBound;
+                mRightEdge.onPull(Math.abs(over) / width);
+                needsInvalidate = true;
+            }
+            scrollX = rightBound;
+        }
+        // Don't lose the rounded component
+        mLastMotionX += scrollX - (int) scrollX;
+        scrollTo((int) scrollX, getScrollY());
+        pageScrolled((int) scrollX);
+
+        return needsInvalidate;
+    }
+
+    /**
+     * @return Info about the page at the current scroll position.
+     *         This can be synthetic for a missing middle page; the 'object' field can be null.
+     */
+    private ItemInfo infoForCurrentScrollPosition() {
+        final int width = getClientWidth();
+        final float scrollOffset = width > 0 ? (float) getScrollX() / width : 0;
+        final float marginOffset = width > 0 ? (float) mPageMargin / width : 0;
+        int lastPos = -1;
+        float lastOffset = 0.f;
+        float lastWidth = 0.f;
+        boolean first = true;
+
+        ItemInfo lastItem = null;
+        for (int i = 0; i < mItems.size(); i++) {
+            ItemInfo ii = mItems.get(i);
+            float offset;
+            if (!first && ii.position != lastPos + 1) {
+                // Create a synthetic item for a missing page.
+                ii = mTempItem;
+                ii.offset = lastOffset + lastWidth + marginOffset;
+                ii.position = lastPos + 1;
+                ii.widthFactor = mAdapter.getPageWidth(ii.position);
+                i--;
+            }
+            offset = ii.offset;
+
+            final float leftBound = offset;
+            final float rightBound = offset + ii.widthFactor + marginOffset;
+            if (first || scrollOffset >= leftBound) {
+                if (scrollOffset < rightBound || i == mItems.size() - 1) {
+                    return ii;
+                }
+            } else {
+                return lastItem;
+            }
+            first = false;
+            lastPos = ii.position;
+            lastOffset = offset;
+            lastWidth = ii.widthFactor;
+            lastItem = ii;
+        }
+
+        return lastItem;
+    }
+
+    private int determineTargetPage(int currentPage, float pageOffset, int velocity, int deltaX) {
+        int targetPage;
+        if (Math.abs(deltaX) > mFlingDistance && Math.abs(velocity) > mMinimumVelocity) {
+            targetPage = velocity > 0 ? currentPage : currentPage + 1;
+        } else {
+            final float truncator = currentPage >= mCurItem ? 0.4f : 0.6f;
+            targetPage = currentPage + (int) (pageOffset + truncator);
+        }
+
+        if (mItems.size() > 0) {
+            final ItemInfo firstItem = mItems.get(0);
+            final ItemInfo lastItem = mItems.get(mItems.size() - 1);
+
+            // Only let the user target pages we have items for
+            targetPage = Math.max(firstItem.position, Math.min(targetPage, lastItem.position));
+        }
+
+        return targetPage;
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        super.draw(canvas);
+        boolean needsInvalidate = false;
+
+        final int overScrollMode = getOverScrollMode();
+        if (overScrollMode == View.OVER_SCROLL_ALWAYS
+                || (overScrollMode == View.OVER_SCROLL_IF_CONTENT_SCROLLS
+                        && mAdapter != null && mAdapter.getCount() > 1)) {
+            if (!mLeftEdge.isFinished()) {
+                final int restoreCount = canvas.save();
+                final int height = getHeight() - getPaddingTop() - getPaddingBottom();
+                final int width = getWidth();
+
+                canvas.rotate(270);
+                canvas.translate(-height + getPaddingTop(), mFirstOffset * width);
+                mLeftEdge.setSize(height, width);
+                needsInvalidate |= mLeftEdge.draw(canvas);
+                canvas.restoreToCount(restoreCount);
+            }
+            if (!mRightEdge.isFinished()) {
+                final int restoreCount = canvas.save();
+                final int width = getWidth();
+                final int height = getHeight() - getPaddingTop() - getPaddingBottom();
+
+                canvas.rotate(90);
+                canvas.translate(-getPaddingTop(), -(mLastOffset + 1) * width);
+                mRightEdge.setSize(height, width);
+                needsInvalidate |= mRightEdge.draw(canvas);
+                canvas.restoreToCount(restoreCount);
+            }
+        } else {
+            mLeftEdge.finish();
+            mRightEdge.finish();
+        }
+
+        if (needsInvalidate) {
+            // Keep animating
+            ViewCompat.postInvalidateOnAnimation(this);
+        }
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+
+        // Draw the margin drawable between pages if needed.
+        if (mPageMargin > 0 && mMarginDrawable != null && mItems.size() > 0 && mAdapter != null) {
+            final int scrollX = getScrollX();
+            final int width = getWidth();
+
+            final float marginOffset = (float) mPageMargin / width;
+            int itemIndex = 0;
+            ItemInfo ii = mItems.get(0);
+            float offset = ii.offset;
+            final int itemCount = mItems.size();
+            final int firstPos = ii.position;
+            final int lastPos = mItems.get(itemCount - 1).position;
+            for (int pos = firstPos; pos < lastPos; pos++) {
+                while (pos > ii.position && itemIndex < itemCount) {
+                    ii = mItems.get(++itemIndex);
+                }
+
+                float drawAt;
+                if (pos == ii.position) {
+                    drawAt = (ii.offset + ii.widthFactor) * width;
+                    offset = ii.offset + ii.widthFactor + marginOffset;
+                } else {
+                    float widthFactor = mAdapter.getPageWidth(pos);
+                    drawAt = (offset + widthFactor) * width;
+                    offset += widthFactor + marginOffset;
+                }
+
+                if (drawAt + mPageMargin > scrollX) {
+                    mMarginDrawable.setBounds(Math.round(drawAt), mTopPageBounds,
+                            Math.round(drawAt + mPageMargin), mBottomPageBounds);
+                    mMarginDrawable.draw(canvas);
+                }
+
+                if (drawAt > scrollX + width) {
+                    break; // No more visible, no sense in continuing
+                }
+            }
+        }
+    }
+
+    /**
+     * Start a fake drag of the pager.
+     *
+     * <p>A fake drag can be useful if you want to synchronize the motion of the ViewPager
+     * with the touch scrolling of another view, while still letting the ViewPager
+     * control the snapping motion and fling behavior. (e.g. parallax-scrolling tabs.)
+     * Call {@link #fakeDragBy(float)} to simulate the actual drag motion. Call
+     * {@link #endFakeDrag()} to complete the fake drag and fling as necessary.
+     *
+     * <p>During a fake drag the ViewPager will ignore all touch events. If a real drag
+     * is already in progress, this method will return false.
+     *
+     * @return true if the fake drag began successfully, false if it could not be started.
+     *
+     * @see #fakeDragBy(float)
+     * @see #endFakeDrag()
+     */
+    public boolean beginFakeDrag() {
+        if (mIsBeingDragged) {
+            return false;
+        }
+        mFakeDragging = true;
+        setScrollState(SCROLL_STATE_DRAGGING);
+        mInitialMotionX = mLastMotionX = 0;
+        if (mVelocityTracker == null) {
+            mVelocityTracker = VelocityTracker.obtain();
+        } else {
+            mVelocityTracker.clear();
+        }
+        final long time = SystemClock.uptimeMillis();
+        final MotionEvent ev = MotionEvent.obtain(time, time, MotionEvent.ACTION_DOWN, 0, 0, 0);
+        mVelocityTracker.addMovement(ev);
+        ev.recycle();
+        mFakeDragBeginTime = time;
+        return true;
+    }
+
+    /**
+     * End a fake drag of the pager.
+     *
+     * @see #beginFakeDrag()
+     * @see #fakeDragBy(float)
+     */
+    public void endFakeDrag() {
+        if (!mFakeDragging) {
+            throw new IllegalStateException("No fake drag in progress. Call beginFakeDrag first.");
+        }
+
+        if (mAdapter != null) {
+            final VelocityTracker velocityTracker = mVelocityTracker;
+            velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
+            int initialVelocity = (int) velocityTracker.getXVelocity(mActivePointerId);
+            mPopulatePending = true;
+            final int width = getClientWidth();
+            final int scrollX = getScrollX();
+            final ItemInfo ii = infoForCurrentScrollPosition();
+            final int currentPage = ii.position;
+            final float pageOffset = (((float) scrollX / width) - ii.offset) / ii.widthFactor;
+            final int totalDelta = (int) (mLastMotionX - mInitialMotionX);
+            int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity,
+                    totalDelta);
+            setCurrentItemInternal(nextPage, true, true, initialVelocity);
+        }
+        endDrag();
+
+        mFakeDragging = false;
+    }
+
+    /**
+     * Fake drag by an offset in pixels. You must have called {@link #beginFakeDrag()} first.
+     *
+     * @param xOffset Offset in pixels to drag by.
+     * @see #beginFakeDrag()
+     * @see #endFakeDrag()
+     */
+    public void fakeDragBy(float xOffset) {
+        if (!mFakeDragging) {
+            throw new IllegalStateException("No fake drag in progress. Call beginFakeDrag first.");
+        }
+
+        if (mAdapter == null) {
+            return;
+        }
+
+        mLastMotionX += xOffset;
+
+        float oldScrollX = getScrollX();
+        float scrollX = oldScrollX - xOffset;
+        final int width = getClientWidth();
+
+        float leftBound = width * mFirstOffset;
+        float rightBound = width * mLastOffset;
+
+        final ItemInfo firstItem = mItems.get(0);
+        final ItemInfo lastItem = mItems.get(mItems.size() - 1);
+        if (firstItem.position != 0) {
+            leftBound = firstItem.offset * width;
+        }
+        if (lastItem.position != mAdapter.getCount() - 1) {
+            rightBound = lastItem.offset * width;
+        }
+
+        if (scrollX < leftBound) {
+            scrollX = leftBound;
+        } else if (scrollX > rightBound) {
+            scrollX = rightBound;
+        }
+        // Don't lose the rounded component
+        mLastMotionX += scrollX - (int) scrollX;
+        scrollTo((int) scrollX, getScrollY());
+        pageScrolled((int) scrollX);
+
+        // Synthesize an event for the VelocityTracker.
+        final long time = SystemClock.uptimeMillis();
+        final MotionEvent ev = MotionEvent.obtain(mFakeDragBeginTime, time, MotionEvent.ACTION_MOVE,
+                mLastMotionX, 0, 0);
+        mVelocityTracker.addMovement(ev);
+        ev.recycle();
+    }
+
+    /**
+     * Returns true if a fake drag is in progress.
+     *
+     * @return true if currently in a fake drag, false otherwise.
+     *
+     * @see #beginFakeDrag()
+     * @see #fakeDragBy(float)
+     * @see #endFakeDrag()
+     */
+    public boolean isFakeDragging() {
+        return mFakeDragging;
+    }
+
+    private void onSecondaryPointerUp(MotionEvent ev) {
+        final int pointerIndex = ev.getActionIndex();
+        final int pointerId = ev.getPointerId(pointerIndex);
+        if (pointerId == mActivePointerId) {
+            // This was our active pointer going up. Choose a new
+            // active pointer and adjust accordingly.
+            final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
+            mLastMotionX = ev.getX(newPointerIndex);
+            mActivePointerId = ev.getPointerId(newPointerIndex);
+            if (mVelocityTracker != null) {
+                mVelocityTracker.clear();
+            }
+        }
+    }
+
+    private void endDrag() {
+        mIsBeingDragged = false;
+        mIsUnableToDrag = false;
+
+        if (mVelocityTracker != null) {
+            mVelocityTracker.recycle();
+            mVelocityTracker = null;
+        }
+    }
+
+    private void setScrollingCacheEnabled(boolean enabled) {
+        if (mScrollingCacheEnabled != enabled) {
+            mScrollingCacheEnabled = enabled;
+            if (USE_CACHE) {
+                final int size = getChildCount();
+                for (int i = 0; i < size; ++i) {
+                    final View child = getChildAt(i);
+                    if (child.getVisibility() != GONE) {
+                        child.setDrawingCacheEnabled(enabled);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Check if this ViewPager can be scrolled horizontally in a certain direction.
+     *
+     * @param direction Negative to check scrolling left, positive to check scrolling right.
+     * @return Whether this ViewPager can be scrolled in the specified direction. It will always
+     *         return false if the specified direction is 0.
+     */
+    @Override
+    public boolean canScrollHorizontally(int direction) {
+        if (mAdapter == null) {
+            return false;
+        }
+
+        final int width = getClientWidth();
+        final int scrollX = getScrollX();
+        if (direction < 0) {
+            return (scrollX > (int) (width * mFirstOffset));
+        } else if (direction > 0) {
+            return (scrollX < (int) (width * mLastOffset));
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Tests scrollability within child views of v given a delta of dx.
+     *
+     * @param v View to test for horizontal scrollability
+     * @param checkV Whether the view v passed should itself be checked for scrollability (true),
+     *               or just its children (false).
+     * @param dx Delta scrolled in pixels
+     * @param x X coordinate of the active touch point
+     * @param y Y coordinate of the active touch point
+     * @return true if child views of v can be scrolled by delta of dx.
+     */
+    protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
+        if (v instanceof ViewGroup) {
+            final ViewGroup group = (ViewGroup) v;
+            final int scrollX = v.getScrollX();
+            final int scrollY = v.getScrollY();
+            final int count = group.getChildCount();
+            // Count backwards - let topmost views consume scroll distance first.
+            for (int i = count - 1; i >= 0; i--) {
+                // TODO: Add versioned support here for transformed views.
+                // This will not work for transformed views in Honeycomb+
+                final View child = group.getChildAt(i);
+                if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight()
+                        && y + scrollY >= child.getTop() && y + scrollY < child.getBottom()
+                        && canScroll(child, true, dx, x + scrollX - child.getLeft(),
+                                y + scrollY - child.getTop())) {
+                    return true;
+                }
+            }
+        }
+
+        return checkV && v.canScrollHorizontally(-dx);
+    }
+
+    @Override
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        // Let the focused view and/or our descendants get the key first
+        return super.dispatchKeyEvent(event) || executeKeyEvent(event);
+    }
+
+    /**
+     * You can call this function yourself to have the scroll view perform
+     * scrolling from a key event, just as if the event had been dispatched to
+     * it by the view hierarchy.
+     *
+     * @param event The key event to execute.
+     * @return Return true if the event was handled, else false.
+     */
+    public boolean executeKeyEvent(@NonNull KeyEvent event) {
+        boolean handled = false;
+        if (event.getAction() == KeyEvent.ACTION_DOWN) {
+            switch (event.getKeyCode()) {
+                case KeyEvent.KEYCODE_DPAD_LEFT:
+                    if (event.hasModifiers(KeyEvent.META_ALT_ON)) {
+                        handled = pageLeft();
+                    } else {
+                        handled = arrowScroll(FOCUS_LEFT);
+                    }
+                    break;
+                case KeyEvent.KEYCODE_DPAD_RIGHT:
+                    if (event.hasModifiers(KeyEvent.META_ALT_ON)) {
+                        handled = pageRight();
+                    } else {
+                        handled = arrowScroll(FOCUS_RIGHT);
+                    }
+                    break;
+                case KeyEvent.KEYCODE_TAB:
+                    if (event.hasNoModifiers()) {
+                        handled = arrowScroll(FOCUS_FORWARD);
+                    } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
+                        handled = arrowScroll(FOCUS_BACKWARD);
+                    }
+                    break;
+            }
+        }
+        return handled;
+    }
+
+    /**
+     * Handle scrolling in response to a left or right arrow click.
+     *
+     * @param direction The direction corresponding to the arrow key that was pressed. It should be
+     *                  either {@link View#FOCUS_LEFT} or {@link View#FOCUS_RIGHT}.
+     * @return Whether the scrolling was handled successfully.
+     */
+    public boolean arrowScroll(int direction) {
+        View currentFocused = findFocus();
+        if (currentFocused == this) {
+            currentFocused = null;
+        } else if (currentFocused != null) {
+            boolean isChild = false;
+            for (ViewParent parent = currentFocused.getParent(); parent instanceof ViewGroup;
+                    parent = parent.getParent()) {
+                if (parent == this) {
+                    isChild = true;
+                    break;
+                }
+            }
+            if (!isChild) {
+                // This would cause the focus search down below to fail in fun ways.
+                final StringBuilder sb = new StringBuilder();
+                sb.append(currentFocused.getClass().getSimpleName());
+                for (ViewParent parent = currentFocused.getParent(); parent instanceof ViewGroup;
+                        parent = parent.getParent()) {
+                    sb.append(" => ").append(parent.getClass().getSimpleName());
+                }
+                Log.e(TAG, "arrowScroll tried to find focus based on non-child "
+                        + "current focused view " + sb.toString());
+                currentFocused = null;
+            }
+        }
+
+        boolean handled = false;
+
+        View nextFocused = FocusFinder.getInstance().findNextFocus(this, currentFocused,
+                direction);
+        if (nextFocused != null && nextFocused != currentFocused) {
+            if (direction == View.FOCUS_LEFT) {
+                // If there is nothing to the left, or this is causing us to
+                // jump to the right, then what we really want to do is page left.
+                final int nextLeft = getChildRectInPagerCoordinates(mTempRect, nextFocused).left;
+                final int currLeft = getChildRectInPagerCoordinates(mTempRect, currentFocused).left;
+                if (currentFocused != null && nextLeft >= currLeft) {
+                    handled = pageLeft();
+                } else {
+                    handled = nextFocused.requestFocus();
+                }
+            } else if (direction == View.FOCUS_RIGHT) {
+                // If there is nothing to the right, or this is causing us to
+                // jump to the left, then what we really want to do is page right.
+                final int nextLeft = getChildRectInPagerCoordinates(mTempRect, nextFocused).left;
+                final int currLeft = getChildRectInPagerCoordinates(mTempRect, currentFocused).left;
+                if (currentFocused != null && nextLeft <= currLeft) {
+                    handled = pageRight();
+                } else {
+                    handled = nextFocused.requestFocus();
+                }
+            }
+        } else if (direction == FOCUS_LEFT || direction == FOCUS_BACKWARD) {
+            // Trying to move left and nothing there; try to page.
+            handled = pageLeft();
+        } else if (direction == FOCUS_RIGHT || direction == FOCUS_FORWARD) {
+            // Trying to move right and nothing there; try to page.
+            handled = pageRight();
+        }
+        if (handled) {
+            playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction));
+        }
+        return handled;
+    }
+
+    private Rect getChildRectInPagerCoordinates(Rect outRect, View child) {
+        if (outRect == null) {
+            outRect = new Rect();
+        }
+        if (child == null) {
+            outRect.set(0, 0, 0, 0);
+            return outRect;
+        }
+        outRect.left = child.getLeft();
+        outRect.right = child.getRight();
+        outRect.top = child.getTop();
+        outRect.bottom = child.getBottom();
+
+        ViewParent parent = child.getParent();
+        while (parent instanceof ViewGroup && parent != this) {
+            final ViewGroup group = (ViewGroup) parent;
+            outRect.left += group.getLeft();
+            outRect.right += group.getRight();
+            outRect.top += group.getTop();
+            outRect.bottom += group.getBottom();
+
+            parent = group.getParent();
+        }
+        return outRect;
+    }
+
+    boolean pageLeft() {
+        if (mCurItem > 0) {
+            setCurrentItem(mCurItem - 1, true);
+            return true;
+        }
+        return false;
+    }
+
+    boolean pageRight() {
+        if (mAdapter != null && mCurItem < (mAdapter.getCount() - 1)) {
+            setCurrentItem(mCurItem + 1, true);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * We only want the current page that is being shown to be focusable.
+     */
+    @Override
+    public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
+        final int focusableCount = views.size();
+
+        final int descendantFocusability = getDescendantFocusability();
+
+        if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
+            for (int i = 0; i < getChildCount(); i++) {
+                final View child = getChildAt(i);
+                if (child.getVisibility() == VISIBLE) {
+                    ItemInfo ii = infoForChild(child);
+                    if (ii != null && ii.position == mCurItem) {
+                        child.addFocusables(views, direction, focusableMode);
+                    }
+                }
+            }
+        }
+
+        // we add ourselves (if focusable) in all cases except for when we are
+        // FOCUS_AFTER_DESCENDANTS and there are some descendants focusable.  this is
+        // to avoid the focus search finding layouts when a more precise search
+        // among the focusable children would be more interesting.
+        if (descendantFocusability != FOCUS_AFTER_DESCENDANTS
+                || (focusableCount == views.size())) { // No focusable descendants
+            // Note that we can't call the superclass here, because it will
+            // add all views in.  So we need to do the same thing View does.
+            if (!isFocusable()) {
+                return;
+            }
+            if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE
+                    && isInTouchMode() && !isFocusableInTouchMode()) {
+                return;
+            }
+            if (views != null) {
+                views.add(this);
+            }
+        }
+    }
+
+    /**
+     * We only want the current page that is being shown to be touchable.
+     */
+    @Override
+    public void addTouchables(ArrayList<View> views) {
+        // Note that we don't call super.addTouchables(), which means that
+        // we don't call View.addTouchables().  This is okay because a ViewPager
+        // is itself not touchable.
+        for (int i = 0; i < getChildCount(); i++) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() == VISIBLE) {
+                ItemInfo ii = infoForChild(child);
+                if (ii != null && ii.position == mCurItem) {
+                    child.addTouchables(views);
+                }
+            }
+        }
+    }
+
+    /**
+     * We only want the current page that is being shown to be focusable.
+     */
+    @Override
+    protected boolean onRequestFocusInDescendants(int direction,
+            Rect previouslyFocusedRect) {
+        int index;
+        int increment;
+        int end;
+        int count = getChildCount();
+        if ((direction & FOCUS_FORWARD) != 0) {
+            index = 0;
+            increment = 1;
+            end = count;
+        } else {
+            index = count - 1;
+            increment = -1;
+            end = -1;
+        }
+        for (int i = index; i != end; i += increment) {
+            View child = getChildAt(i);
+            if (child.getVisibility() == VISIBLE) {
+                ItemInfo ii = infoForChild(child);
+                if (ii != null && ii.position == mCurItem) {
+                    if (child.requestFocus(direction, previouslyFocusedRect)) {
+                        return true;
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+        // Dispatch scroll events from this ViewPager.
+        if (event.getEventType() == AccessibilityEventCompat.TYPE_VIEW_SCROLLED) {
+            return super.dispatchPopulateAccessibilityEvent(event);
+        }
+
+        // Dispatch all other accessibility events from the current page.
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() == VISIBLE) {
+                final ItemInfo ii = infoForChild(child);
+                if (ii != null && ii.position == mCurItem
+                        && child.dispatchPopulateAccessibilityEvent(event)) {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    @Override
+    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
+        return new LayoutParams();
+    }
+
+    @Override
+    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
+        return generateDefaultLayoutParams();
+    }
+
+    @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);
+    }
+
+    class MyAccessibilityDelegate extends AccessibilityDelegateCompat {
+
+        @Override
+        public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
+            super.onInitializeAccessibilityEvent(host, event);
+            event.setClassName(ViewPager.class.getName());
+            event.setScrollable(canScroll());
+            if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED && mAdapter != null) {
+                event.setItemCount(mAdapter.getCount());
+                event.setFromIndex(mCurItem);
+                event.setToIndex(mCurItem);
+            }
+        }
+
+        @Override
+        public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
+            super.onInitializeAccessibilityNodeInfo(host, info);
+            info.setClassName(ViewPager.class.getName());
+            info.setScrollable(canScroll());
+            if (canScrollHorizontally(1)) {
+                info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD);
+            }
+            if (canScrollHorizontally(-1)) {
+                info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD);
+            }
+        }
+
+        @Override
+        public boolean performAccessibilityAction(View host, int action, Bundle args) {
+            if (super.performAccessibilityAction(host, action, args)) {
+                return true;
+            }
+            switch (action) {
+                case AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD: {
+                    if (canScrollHorizontally(1)) {
+                        setCurrentItem(mCurItem + 1);
+                        return true;
+                    }
+                } return false;
+                case AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD: {
+                    if (canScrollHorizontally(-1)) {
+                        setCurrentItem(mCurItem - 1);
+                        return true;
+                    }
+                } return false;
+            }
+            return false;
+        }
+
+        private boolean canScroll() {
+            return (mAdapter != null) && (mAdapter.getCount() > 1);
+        }
+    }
+
+    private class PagerObserver extends DataSetObserver {
+        PagerObserver() {
+        }
+
+        @Override
+        public void onChanged() {
+            dataSetChanged();
+        }
+        @Override
+        public void onInvalidated() {
+            dataSetChanged();
+        }
+    }
+
+    /**
+     * Layout parameters that should be supplied for views added to a
+     * ViewPager.
+     */
+    public static class LayoutParams extends ViewGroup.LayoutParams {
+        /**
+         * true if this view is a decoration on the pager itself and not
+         * a view supplied by the adapter.
+         */
+        public boolean isDecor;
+
+        /**
+         * Gravity setting for use on decor views only:
+         * Where to position the view page within the overall ViewPager
+         * container; constants are defined in {@link android.view.Gravity}.
+         */
+        public int gravity;
+
+        /**
+         * Width as a 0-1 multiplier of the measured pager width
+         */
+        float widthFactor = 0.f;
+
+        /**
+         * true if this view was added during layout and needs to be measured
+         * before being positioned.
+         */
+        boolean needsMeasure;
+
+        /**
+         * Adapter position this view is for if !isDecor
+         */
+        int position;
+
+        /**
+         * Current child index within the ViewPager that this view occupies
+         */
+        int childIndex;
+
+        public LayoutParams() {
+            super(MATCH_PARENT, MATCH_PARENT);
+        }
+
+        public LayoutParams(Context context, AttributeSet attrs) {
+            super(context, attrs);
+
+            final TypedArray a = context.obtainStyledAttributes(attrs, LAYOUT_ATTRS);
+            gravity = a.getInteger(0, Gravity.TOP);
+            a.recycle();
+        }
+    }
+
+    static class ViewPositionComparator implements Comparator<View> {
+        @Override
+        public int compare(View lhs, View rhs) {
+            final LayoutParams llp = (LayoutParams) lhs.getLayoutParams();
+            final LayoutParams rlp = (LayoutParams) rhs.getLayoutParams();
+            if (llp.isDecor != rlp.isDecor) {
+                return llp.isDecor ? 1 : -1;
+            }
+            return llp.position - rlp.position;
+        }
+    }
+}
diff --git a/wear/build.gradle b/wear/build.gradle
index 2eccacb..2b832e7 100644
--- a/wear/build.gradle
+++ b/wear/build.gradle
@@ -11,7 +11,7 @@
     api(project(":support-core-ui"))
     api(project(":support-fragment"))
     api(project(":recyclerview-v7"))
-    api(CONSTRAINT_LAYOUT)
+    api(CONSTRAINT_LAYOUT, { transitive = true })
 
     androidTestImplementation(TEST_RUNNER)
     androidTestImplementation(ESPRESSO_CORE)
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-af/strings.xml b/wear/res/values-af/strings.xml
new file mode 100644
index 0000000..6bc9a46
--- /dev/null
+++ b/wear/res/values-af/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Navigasielaai"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Handelinglaai"</string>
+</resources>
diff --git a/wear/res/values-am/strings.xml b/wear/res/values-am/strings.xml
new file mode 100644
index 0000000..3918be4
--- /dev/null
+++ b/wear/res/values-am/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"የአሰሳ መሳቢያ"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"የእርምጃ መሳቢያ"</string>
+</resources>
diff --git a/wear/res/values-ar/strings.xml b/wear/res/values-ar/strings.xml
new file mode 100644
index 0000000..89f8f10
--- /dev/null
+++ b/wear/res/values-ar/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"لائحة التنقل"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"دُرج الإجراءات"</string>
+</resources>
diff --git a/wear/res/values-az/strings.xml b/wear/res/values-az/strings.xml
new file mode 100644
index 0000000..25d3c3b
--- /dev/null
+++ b/wear/res/values-az/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Naviqasiya qutusu"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Əməliyyat qutusu"</string>
+</resources>
diff --git a/wear/res/values-b+sr+Latn/strings.xml b/wear/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..b3c2c22
--- /dev/null
+++ b/wear/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Fioka za navigaciju"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Fioka za radnju"</string>
+</resources>
diff --git a/wear/res/values-be/strings.xml b/wear/res/values-be/strings.xml
new file mode 100644
index 0000000..ee3c17c
--- /dev/null
+++ b/wear/res/values-be/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Высоўнае меню навігацыі"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Высоўнае меню дзеянняў"</string>
+</resources>
diff --git a/wear/res/values-bg/strings.xml b/wear/res/values-bg/strings.xml
new file mode 100644
index 0000000..0ed041b
--- /dev/null
+++ b/wear/res/values-bg/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Слой за навигация"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Слой за действия"</string>
+</resources>
diff --git a/wear/res/values-bn/strings.xml b/wear/res/values-bn/strings.xml
new file mode 100644
index 0000000..48bea20
--- /dev/null
+++ b/wear/res/values-bn/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"নেভিগেশন ড্রয়ার"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"অ্যাকশন ড্রয়ার"</string>
+</resources>
diff --git a/wear/res/values-bs/strings.xml b/wear/res/values-bs/strings.xml
new file mode 100644
index 0000000..82c990c
--- /dev/null
+++ b/wear/res/values-bs/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Panel za navigaciju"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Panel za radnju"</string>
+</resources>
diff --git a/wear/res/values-ca/strings.xml b/wear/res/values-ca/strings.xml
new file mode 100644
index 0000000..e11bd6f
--- /dev/null
+++ b/wear/res/values-ca/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Tauler de navegació"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Tauler d\'accions"</string>
+</resources>
diff --git a/wear/res/values-cs/strings.xml b/wear/res/values-cs/strings.xml
new file mode 100644
index 0000000..01a6c72
--- /dev/null
+++ b/wear/res/values-cs/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Vysouvací panel navigace"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Vysouvací panel akcí"</string>
+</resources>
diff --git a/wear/res/values-da/strings.xml b/wear/res/values-da/strings.xml
new file mode 100644
index 0000000..ddafa9e
--- /dev/null
+++ b/wear/res/values-da/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Sidemenu"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Handlingsmenu"</string>
+</resources>
diff --git a/wear/res/values-de/strings.xml b/wear/res/values-de/strings.xml
new file mode 100644
index 0000000..cd463f1
--- /dev/null
+++ b/wear/res/values-de/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Navigationsleiste"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Aktionsleiste"</string>
+</resources>
diff --git a/wear/res/values-el/strings.xml b/wear/res/values-el/strings.xml
new file mode 100644
index 0000000..e1ae01b
--- /dev/null
+++ b/wear/res/values-el/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Συρτάρι πλοήγησης"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Συρτάρι ενεργειών"</string>
+</resources>
diff --git a/wear/res/values-en-rAU/strings.xml b/wear/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000..ad16473
--- /dev/null
+++ b/wear/res/values-en-rAU/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Navigation drawer"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Action drawer"</string>
+</resources>
diff --git a/wear/res/values-en-rCA/strings.xml b/wear/res/values-en-rCA/strings.xml
new file mode 100644
index 0000000..ad16473
--- /dev/null
+++ b/wear/res/values-en-rCA/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Navigation drawer"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Action drawer"</string>
+</resources>
diff --git a/wear/res/values-en-rGB/strings.xml b/wear/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..ad16473
--- /dev/null
+++ b/wear/res/values-en-rGB/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Navigation drawer"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Action drawer"</string>
+</resources>
diff --git a/wear/res/values-en-rIN/strings.xml b/wear/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..ad16473
--- /dev/null
+++ b/wear/res/values-en-rIN/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Navigation drawer"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Action drawer"</string>
+</resources>
diff --git a/wear/res/values-en-rXC/strings.xml b/wear/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000..b1f533e
--- /dev/null
+++ b/wear/res/values-en-rXC/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‏‎‎‏‏‎‏‏‎‏‏‎‏‏‏‏‏‎‏‎‎‎‏‏‎‎‏‎‎‏‎‎‏‏‎‎‏‎‎‎‎‎‏‏‎‏‎‏‎‎‎‏‏‏‎Navigation drawer‎‏‎‎‏‎"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‏‎‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‎‎‎‏‏‏‎‎‏‏‎‏‎‏‎‎‏‎‏‎‏‎‏‎‎‎‎‎‎‏‏‏‎‏‎‎‏‎‎‏‎Action drawer‎‏‎‎‏‎"</string>
+</resources>
diff --git a/wear/res/values-es-rUS/strings.xml b/wear/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..7f5141d
--- /dev/null
+++ b/wear/res/values-es-rUS/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Panel lateral de navegación"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Panel lateral de acciones"</string>
+</resources>
diff --git a/wear/res/values-es/strings.xml b/wear/res/values-es/strings.xml
new file mode 100644
index 0000000..178fc8b
--- /dev/null
+++ b/wear/res/values-es/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Panel de navegación"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Panel de acciones"</string>
+</resources>
diff --git a/wear/res/values-et/strings.xml b/wear/res/values-et/strings.xml
new file mode 100644
index 0000000..a7d04f0
--- /dev/null
+++ b/wear/res/values-et/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Navigeerimissahtel"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Toimingusahtel"</string>
+</resources>
diff --git a/wear/res/values-eu/strings.xml b/wear/res/values-eu/strings.xml
new file mode 100644
index 0000000..353d3c6
--- /dev/null
+++ b/wear/res/values-eu/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Nabigazio-panel lerrakorra"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Ekintza-panel lerrakorra"</string>
+</resources>
diff --git a/wear/res/values-fa/strings.xml b/wear/res/values-fa/strings.xml
new file mode 100644
index 0000000..62b8e1a
--- /dev/null
+++ b/wear/res/values-fa/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"کشوی پیمایش"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"کشوی فعالیت"</string>
+</resources>
diff --git a/wear/res/values-fi/strings.xml b/wear/res/values-fi/strings.xml
new file mode 100644
index 0000000..bc96258
--- /dev/null
+++ b/wear/res/values-fi/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Navigoinnin vetopaneeli"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Toimintojen vetopaneeli"</string>
+</resources>
diff --git a/wear/res/values-fr-rCA/strings.xml b/wear/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..5a284c2
--- /dev/null
+++ b/wear/res/values-fr-rCA/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Panneau de navigation"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Panneau d\'actions"</string>
+</resources>
diff --git a/wear/res/values-fr/strings.xml b/wear/res/values-fr/strings.xml
new file mode 100644
index 0000000..2762885
--- /dev/null
+++ b/wear/res/values-fr/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Panneau de navigation"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Panneau de commandes"</string>
+</resources>
diff --git a/wear/res/values-gl/strings.xml b/wear/res/values-gl/strings.xml
new file mode 100644
index 0000000..3c80d82
--- /dev/null
+++ b/wear/res/values-gl/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Panel de navegación"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Panel de accións"</string>
+</resources>
diff --git a/wear/res/values-gu/strings.xml b/wear/res/values-gu/strings.xml
new file mode 100644
index 0000000..18704b9
--- /dev/null
+++ b/wear/res/values-gu/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"નૅવિગેશન ડ્રોઅર"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"ઍક્શન ડ્રોઅર"</string>
+</resources>
diff --git a/wear/res/values-hi/strings.xml b/wear/res/values-hi/strings.xml
new file mode 100644
index 0000000..931dd5b
--- /dev/null
+++ b/wear/res/values-hi/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"नेविगेशन पैनल"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"कार्रवाई पैनल"</string>
+</resources>
diff --git a/wear/res/values-hr/strings.xml b/wear/res/values-hr/strings.xml
new file mode 100644
index 0000000..cf30702
--- /dev/null
+++ b/wear/res/values-hr/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Ladica za navigaciju"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Ladica za radnju"</string>
+</resources>
diff --git a/wear/res/values-hu/strings.xml b/wear/res/values-hu/strings.xml
new file mode 100644
index 0000000..7956166
--- /dev/null
+++ b/wear/res/values-hu/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Navigációs fiók"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Műveleti fiók"</string>
+</resources>
diff --git a/wear/res/values-hy/strings.xml b/wear/res/values-hy/strings.xml
new file mode 100644
index 0000000..2ed20e3
--- /dev/null
+++ b/wear/res/values-hy/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Նավարկման դարակ"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Գործողությունների դարակ"</string>
+</resources>
diff --git a/wear/res/values-in/strings.xml b/wear/res/values-in/strings.xml
new file mode 100644
index 0000000..a4014a6
--- /dev/null
+++ b/wear/res/values-in/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Panel navigasi"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Panel samping tindakan"</string>
+</resources>
diff --git a/wear/res/values-is/strings.xml b/wear/res/values-is/strings.xml
new file mode 100644
index 0000000..5100ca2
--- /dev/null
+++ b/wear/res/values-is/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Yfirlitsskúffa"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Aðgerðaskúffa"</string>
+</resources>
diff --git a/wear/res/values-it/strings.xml b/wear/res/values-it/strings.xml
new file mode 100644
index 0000000..680267d
--- /dev/null
+++ b/wear/res/values-it/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Riquadro di navigazione a scomparsa"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Riquadro a scomparsa delle azioni"</string>
+</resources>
diff --git a/wear/res/values-iw/strings.xml b/wear/res/values-iw/strings.xml
new file mode 100644
index 0000000..bf45234
--- /dev/null
+++ b/wear/res/values-iw/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"חלונית הזזה לניווט"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"חלונית הזזה לפעולות"</string>
+</resources>
diff --git a/wear/res/values-ja/strings.xml b/wear/res/values-ja/strings.xml
new file mode 100644
index 0000000..cd96bad
--- /dev/null
+++ b/wear/res/values-ja/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"ナビゲーション ドロワー"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"アクション ドロワー"</string>
+</resources>
diff --git a/wear/res/values-ka/strings.xml b/wear/res/values-ka/strings.xml
new file mode 100644
index 0000000..ba15c3b
--- /dev/null
+++ b/wear/res/values-ka/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"ნავიგაციის უჯრა"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"ქმედების უჯრა"</string>
+</resources>
diff --git a/wear/res/values-kk/strings.xml b/wear/res/values-kk/strings.xml
new file mode 100644
index 0000000..a4e3343
--- /dev/null
+++ b/wear/res/values-kk/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Навигация тартпасы"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Әрекеттер тартпасы"</string>
+</resources>
diff --git a/wear/res/values-km/strings.xml b/wear/res/values-km/strings.xml
new file mode 100644
index 0000000..db04750
--- /dev/null
+++ b/wear/res/values-km/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"ថត​រុករក"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"ថត​សកម្មភាព"</string>
+</resources>
diff --git a/wear/res/values-kn/strings.xml b/wear/res/values-kn/strings.xml
new file mode 100644
index 0000000..b2edb49
--- /dev/null
+++ b/wear/res/values-kn/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"ನ್ಯಾವಿಗೇಶನ್ ಡ್ರಾಯರ್"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"ಕ್ರಿಯೆ ಡ್ರಾಯರ್"</string>
+</resources>
diff --git a/wear/res/values-ko/strings.xml b/wear/res/values-ko/strings.xml
new file mode 100644
index 0000000..1c4c58e
--- /dev/null
+++ b/wear/res/values-ko/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"탐색 창"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"작업 창"</string>
+</resources>
diff --git a/wear/res/values-ky/strings.xml b/wear/res/values-ky/strings.xml
new file mode 100644
index 0000000..821cb35
--- /dev/null
+++ b/wear/res/values-ky/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Чабыттоо суурмасы"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Аракет суурмасы"</string>
+</resources>
diff --git a/wear/res/values-lo/strings.xml b/wear/res/values-lo/strings.xml
new file mode 100644
index 0000000..82b3403
--- /dev/null
+++ b/wear/res/values-lo/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"ແຖບການນຳທາງ"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"ແຖບຄຳສັ່ງ"</string>
+</resources>
diff --git a/wear/res/values-lt/strings.xml b/wear/res/values-lt/strings.xml
new file mode 100644
index 0000000..c08f1be
--- /dev/null
+++ b/wear/res/values-lt/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Naršymo skydelis"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Veiksmo skydelis"</string>
+</resources>
diff --git a/wear/res/values-lv/strings.xml b/wear/res/values-lv/strings.xml
new file mode 100644
index 0000000..233b9de
--- /dev/null
+++ b/wear/res/values-lv/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Navigācijas atvilktne"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Darbību atvilktne"</string>
+</resources>
diff --git a/wear/res/values-mk/strings.xml b/wear/res/values-mk/strings.xml
new file mode 100644
index 0000000..3ba4480
--- /dev/null
+++ b/wear/res/values-mk/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Фиока за навигација"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Фиока за дејство"</string>
+</resources>
diff --git a/wear/res/values-ml/strings.xml b/wear/res/values-ml/strings.xml
new file mode 100644
index 0000000..45527cd
--- /dev/null
+++ b/wear/res/values-ml/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"നാവിഗേഷൻ ഡ്രോയർ"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"ആക്ഷൻ ഡ്രോയർ"</string>
+</resources>
diff --git a/wear/res/values-mn/strings.xml b/wear/res/values-mn/strings.xml
new file mode 100644
index 0000000..53c4dec
--- /dev/null
+++ b/wear/res/values-mn/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Навигацийн шургуулга"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Үйлдлийн татуурга"</string>
+</resources>
diff --git a/wear/res/values-mr/strings.xml b/wear/res/values-mr/strings.xml
new file mode 100644
index 0000000..20b5072
--- /dev/null
+++ b/wear/res/values-mr/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"नेव्हिगेशन ड्रॉवर"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"क्रिया ड्रॉवर"</string>
+</resources>
diff --git a/wear/res/values-ms/strings.xml b/wear/res/values-ms/strings.xml
new file mode 100644
index 0000000..e0ab113
--- /dev/null
+++ b/wear/res/values-ms/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Laci navigasi"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Laci tindakan"</string>
+</resources>
diff --git a/wear/res/values-my/strings.xml b/wear/res/values-my/strings.xml
new file mode 100644
index 0000000..1d7c401
--- /dev/null
+++ b/wear/res/values-my/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"လမ်းကြောင်းပြ အံဆွဲ"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"လုပ်ဆောင်ချက် အံဆွဲ"</string>
+</resources>
diff --git a/wear/res/values-nb/strings.xml b/wear/res/values-nb/strings.xml
new file mode 100644
index 0000000..fdd65d5
--- /dev/null
+++ b/wear/res/values-nb/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Uttrekksmeny"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Uttrekksmeny for handlinger"</string>
+</resources>
diff --git a/wear/res/values-ne/strings.xml b/wear/res/values-ne/strings.xml
new file mode 100644
index 0000000..b524cf5
--- /dev/null
+++ b/wear/res/values-ne/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"नेभिगेसन ड्रअर"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"कारबाहीसम्बन्धी ड्रअर"</string>
+</resources>
diff --git a/wear/res/values-nl/strings.xml b/wear/res/values-nl/strings.xml
new file mode 100644
index 0000000..d7d7fdf
--- /dev/null
+++ b/wear/res/values-nl/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Zijmenu"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Actiemenu"</string>
+</resources>
diff --git a/wear/res/values-pa/strings.xml b/wear/res/values-pa/strings.xml
new file mode 100644
index 0000000..afb5599
--- /dev/null
+++ b/wear/res/values-pa/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"ਦਿਸ਼ਾ-ਨਿਰਦੇਸ਼ ਡ੍ਰਾਅਰ"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"ਕਾਰਵਾਈ ਡ੍ਰਾਅਰ"</string>
+</resources>
diff --git a/wear/res/values-pl/strings.xml b/wear/res/values-pl/strings.xml
new file mode 100644
index 0000000..de964e7
--- /dev/null
+++ b/wear/res/values-pl/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Panel nawigacji"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Panel działań"</string>
+</resources>
diff --git a/wear/res/values-pt-rBR/strings.xml b/wear/res/values-pt-rBR/strings.xml
new file mode 100644
index 0000000..6347156
--- /dev/null
+++ b/wear/res/values-pt-rBR/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Gaveta de navegação"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Gaveta de ações"</string>
+</resources>
diff --git a/wear/res/values-pt-rPT/strings.xml b/wear/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..6347156
--- /dev/null
+++ b/wear/res/values-pt-rPT/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Gaveta de navegação"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Gaveta de ações"</string>
+</resources>
diff --git a/wear/res/values-pt/strings.xml b/wear/res/values-pt/strings.xml
new file mode 100644
index 0000000..6347156
--- /dev/null
+++ b/wear/res/values-pt/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Gaveta de navegação"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Gaveta de ações"</string>
+</resources>
diff --git a/wear/res/values-ro/strings.xml b/wear/res/values-ro/strings.xml
new file mode 100644
index 0000000..6f6aa10
--- /dev/null
+++ b/wear/res/values-ro/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Panou de navigare"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Panou de acțiune"</string>
+</resources>
diff --git a/wear/res/values-ru/strings.xml b/wear/res/values-ru/strings.xml
new file mode 100644
index 0000000..7d3a266
--- /dev/null
+++ b/wear/res/values-ru/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Панель навигации"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Панель действий"</string>
+</resources>
diff --git a/wear/res/values-si/strings.xml b/wear/res/values-si/strings.xml
new file mode 100644
index 0000000..4ae2f63
--- /dev/null
+++ b/wear/res/values-si/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"සංචාලන ලාච්චුව"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"ක්‍රියාමාර්ග ලාච්චුව"</string>
+</resources>
diff --git a/wear/res/values-sk/strings.xml b/wear/res/values-sk/strings.xml
new file mode 100644
index 0000000..cbb2c6a
--- /dev/null
+++ b/wear/res/values-sk/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Navigačný vysúvací panel"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Vysúvací panel akcií"</string>
+</resources>
diff --git a/wear/res/values-sl/strings.xml b/wear/res/values-sl/strings.xml
new file mode 100644
index 0000000..e7aa38c
--- /dev/null
+++ b/wear/res/values-sl/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Predal za krmarjenje"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Predal z dejanji"</string>
+</resources>
diff --git a/wear/res/values-sq/strings.xml b/wear/res/values-sq/strings.xml
new file mode 100644
index 0000000..1b18aba
--- /dev/null
+++ b/wear/res/values-sq/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Sirtari i navigimit"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Sirtari i veprimit"</string>
+</resources>
diff --git a/wear/res/values-sr/strings.xml b/wear/res/values-sr/strings.xml
new file mode 100644
index 0000000..c2a6ff7
--- /dev/null
+++ b/wear/res/values-sr/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Фиока за навигацију"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Фиока за радњу"</string>
+</resources>
diff --git a/wear/res/values-sv/strings.xml b/wear/res/values-sv/strings.xml
new file mode 100644
index 0000000..c5c07a6
--- /dev/null
+++ b/wear/res/values-sv/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Navigeringspanel"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Åtgärdspanel"</string>
+</resources>
diff --git a/wear/res/values-sw/strings.xml b/wear/res/values-sw/strings.xml
new file mode 100644
index 0000000..2f4bcc0
--- /dev/null
+++ b/wear/res/values-sw/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Droo ya kusogeza"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Droo ya vitendo"</string>
+</resources>
diff --git a/wear/res/values-ta/strings.xml b/wear/res/values-ta/strings.xml
new file mode 100644
index 0000000..ccfed38
--- /dev/null
+++ b/wear/res/values-ta/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"வழிசெலுத்தல் டிராயர்"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"செயல் டிராயர்"</string>
+</resources>
diff --git a/wear/res/values-te/strings.xml b/wear/res/values-te/strings.xml
new file mode 100644
index 0000000..c3db02c
--- /dev/null
+++ b/wear/res/values-te/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"నావిగేషన్ డ్రాయర్"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"చర్య డ్రాయర్"</string>
+</resources>
diff --git a/wear/res/values-th/strings.xml b/wear/res/values-th/strings.xml
new file mode 100644
index 0000000..f5b0521
--- /dev/null
+++ b/wear/res/values-th/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"ลิ้นชักการนำทาง"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"ลิ้นชักการดำเนินการ"</string>
+</resources>
diff --git a/wear/res/values-tl/strings.xml b/wear/res/values-tl/strings.xml
new file mode 100644
index 0000000..ad16473
--- /dev/null
+++ b/wear/res/values-tl/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Navigation drawer"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Action drawer"</string>
+</resources>
diff --git a/wear/res/values-tr/strings.xml b/wear/res/values-tr/strings.xml
new file mode 100644
index 0000000..32aff20
--- /dev/null
+++ b/wear/res/values-tr/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Gezinme çekmecesi"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"İşlem çekmecesi"</string>
+</resources>
diff --git a/wear/res/values-uk/strings.xml b/wear/res/values-uk/strings.xml
new file mode 100644
index 0000000..93d9432
--- /dev/null
+++ b/wear/res/values-uk/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Панель навігації"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Висувна панель команд"</string>
+</resources>
diff --git a/wear/res/values-ur/strings.xml b/wear/res/values-ur/strings.xml
new file mode 100644
index 0000000..53b133e
--- /dev/null
+++ b/wear/res/values-ur/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"نیویگیشن دراز"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"کارروائی دراز"</string>
+</resources>
diff --git a/wear/res/values-uz/strings.xml b/wear/res/values-uz/strings.xml
new file mode 100644
index 0000000..a09fef7
--- /dev/null
+++ b/wear/res/values-uz/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Navigatsiya paneli"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Buyruqlar paneli"</string>
+</resources>
diff --git a/wear/res/values-vi/strings.xml b/wear/res/values-vi/strings.xml
new file mode 100644
index 0000000..d42c495
--- /dev/null
+++ b/wear/res/values-vi/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Ngăn điều hướng"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Ngăn tác vụ"</string>
+</resources>
diff --git a/wear/res/values-zh-rCN/strings.xml b/wear/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..1fbb17e
--- /dev/null
+++ b/wear/res/values-zh-rCN/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"抽屉式导航栏"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"操作抽屉式导航栏"</string>
+</resources>
diff --git a/wear/res/values-zh-rHK/strings.xml b/wear/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..7e96db7
--- /dev/null
+++ b/wear/res/values-zh-rHK/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"導覽列"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"操作導覽列"</string>
+</resources>
diff --git a/wear/res/values-zh-rTW/strings.xml b/wear/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..b2ca4a2
--- /dev/null
+++ b/wear/res/values-zh-rTW/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"導覽匣"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"動作導覽匣"</string>
+</resources>
diff --git a/wear/res/values-zu/strings.xml b/wear/res/values-zu/strings.xml
new file mode 100644
index 0000000..609f735
--- /dev/null
+++ b/wear/res/values-zu/strings.xml
@@ -0,0 +1,21 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="ws_navigation_drawer_content_description" msgid="7216697245762194759">"Ikhabethe lokuzulazula"</string>
+    <string name="ws_action_drawer_content_description" msgid="1837365417701148489">"Ikhabethe lesenzo"</string>
+</resources>
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/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/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 e4fff11..7975fc8 100644
--- a/webkit/build.gradle
+++ b/webkit/build.gradle
@@ -13,20 +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 = 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/AndroidManifest.xml b/webkit/src/main/AndroidManifest.xml
similarity index 100%
rename from webkit/AndroidManifest.xml
rename to webkit/src/main/AndroidManifest.xml
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.